Skip to content

Stable sync 7.73.2#29379

Merged
joaoloureirop merged 148 commits into
release/7.74.00from
stable-sync-7.73.2
Apr 27, 2026
Merged

Stable sync 7.73.2#29379
joaoloureirop merged 148 commits into
release/7.74.00from
stable-sync-7.73.2

Conversation

@joaoloureirop
Copy link
Copy Markdown
Contributor

Description

the previous sync was merged with a squash commit, failing to address the merge conflicts of the release branch.

This PR should be merged via a merge commit

Changelog

CHANGELOG entry:

Related issues

Fixes:

Manual testing steps

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

After

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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.

metamaskbot and others added 30 commits April 2, 2026 19:48
…-token UX from UAT issues cp-7.73.0 (#28371)

- fix(predict): improve Predict buy-with-any-token UX from UAT issues
cp-7.73.0 (#28302)

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

Addresses several UAT issues in the Predict buy-with-any-token flow:

- **Auto-select best payment token**: New
`usePredictDefaultPaymentToken` hook auto-selects the token with the
highest fiat balance when Predict balance is below MINIMUM_BET ($1),
instead of requiring manual selection. Resets to Predict balance when
sufficient.
- **Optimistic positions on deposit**: Creates optimistic positions from
the order preview at deposit time so the position appears immediately in
the portfolio while the deposit confirms. Clears optimistic positions on
failure (both direct order failures and failed deposit-and-order
transactions).
- **Navigate back on deposit**: Navigate back when the deposit-and-order
flow begins, so the user isn't stuck on the buy form.
- **Keep token selection always enabled**: Removes the `canSelectToken`
gate — the pay-with-token row is now always interactive (disabled only
while placing an order).
- **"Predict balance first" hint**: Shows "Your Predict balance will be
used first" below the pay-with row when an external token is selected,
so users understand the payment order.
- **Deposit amount guards**: `depositAmount` now returns 0 when the
preview is unavailable or the bet is below minimum, preventing premature
deposit calculations and stale values from triggering the deposit flow.
- **Updated insufficient funds messaging**: Error messages now suggest
trying a different token when funds are insufficient.
- **Fix text overflow on Polymarket terms**: Nests the "learn more" link
inside the disclaimer text and adds horizontal padding to prevent
overflow.
- **Fix premature payment token reset**: Adds a
`totalPayForPredictBalance > 0` guard so the auto-reset effect only
fires when there is an actual bet amount, preventing the selected token
from being cleared immediately after selection.
- **Depositing toast notification**: Shows a "Prediction in progress"
toast with spinner when the deposit phase begins and invalidates
position queries to reflect the optimistic position.


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

https://www.loom.com/share/c25681fd77a444e496f999a23a55b0e6

<!-- 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]
> **Medium Risk**
> Updates buy-with-any-token order state transitions, optimistic
position caching, and navigation/toast behavior; mistakes could cause
incorrect UI state or stale/phantom positions during deposit/order
failures.
> 
> **Overview**
> Improves the *buy-with-any-token* flow by introducing a new `order`
event status `depositing` and publishing it when the flow transitions
into the deposit phase, with a matching “Prediction in progress” toast
and positions query invalidation.
> 
> Adds preview-based **optimistic positions** during deposit via
`PolymarketProvider.createOptimisticPositionFromPreview`, and ensures
cleanup via `clearOptimisticPosition` when `placeOrder` fails or when a
`depositAndOrder` transaction fails.
> 
> Refines buy screen UX: auto-selects a default payment token when
Predict balance is below `MINIMUM_BET` (new
`usePredictDefaultPaymentToken`), removes the `canSelectToken` gate (row
only disabled while placing), navigates back when entering `DEPOSITING`,
adds a “Predict balance will be used first” hint, guards deposit amount
calculation until fees/minimum bet are available, and updates
insufficient-funds copy to suggest trying another token; also adjusts
the Polymarket TOS disclaimer layout to prevent overflow.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7f97218. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[fda751e](fda751e)

Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
…aused by token warning in unified swaps context cp-7.73.0 (#28366)

- fix: prevent infinite quote request loop caused by token warning in
unified swaps context cp-7.73.0 (#28361)

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

When a destination token has a security warning (e.g. a Blockaid
malicious/suspicious flag), the unified swaps bridge view was entering
an infinite quote request loop.

**Root cause:** `tokenWarning` was included as a dependency of the
`useMemo` that builds the analytics `context` object in
`useUnifiedSwapBridgeContext`. `tokenWarning` is itself derived from
quote results (blockaid data returned by the bridge controller). This
created a feedback cycle:

```
Quote fetched → tokenWarning updates → context object recreates
→ updateQuoteParams identity changes → useEffect fires
→ new quote request → repeat ∞
```

**Fix:** Remove `tokenWarning` from the `useMemo` dependency array and
clear `security_warnings` to `[]` for now. The `security_warnings` field
will be populated properly in the bridge controller instead, removing
the React dependency cycle entirely.

## **Changelog**

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

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

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

CHANGELOG entry: Fixed a bug that caused repeated quote requests when
swapping to a token with a security warning.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Unified Swaps/Bridge quote fetching with token warnings

  Scenario: user swaps to a token with a Blockaid security warning
    Given the user has opened the Swap/Bridge screen
    And the user has selected a source token with sufficient balance

    When the user selects a destination token that has a Blockaid security warning
    And the user enters a valid source amount
    Then the app fetches a quote once
    And does not repeatedly fire additional quote requests
    And the security warning banner is displayed on screen

  Scenario: user swaps to a normal token (no warning)
    Given the user has opened the Swap/Bridge screen
    And the user has selected a source token with sufficient balance

    When the user selects a destination token with no security warning
    And the user enters a valid source amount
    Then the app fetches a quote once
    And quote results are displayed normally
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**


Uploading Screen Recording 2026-04-02 at 4.24.51 PM.mov…



## **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 the help of the pr-description AI skill -->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: small change limited to analytics context memoization, but
it temporarily drops `security_warnings` data which could affect
warning-related telemetry until re-populated elsewhere.
> 
> **Overview**
> Prevents an infinite bridge quote re-fetch loop by removing
destination token warning state from `useUnifiedSwapBridgeContext`’s
memoized context object.
> 
> `security_warnings` is now always an empty array (*TODO*) and the
`useMemo` dependency list no longer includes the warning selector,
stabilizing the `context` identity passed into
`BridgeController.updateBridgeQuoteRequestParams`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
21dec81. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[b155157](b155157)

Co-authored-by: infiniteflower <139582705+infiniteflower@users.noreply.github.com>
…pened event cp-7.73.0 (#28377)

- fix: add hasPerpsMarket to token details opened event cp-7.73.0
(#28242)

## **Description**

Updates the TOKEN_DETAILS_OPENED analytics event to include
has_perps_market and severity properties, providing richer context about
the token details screen state when the event fires.

## **Changelog**

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

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

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

CHANGELOG entry: adds event property to token details opened event

## **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]
> **Medium Risk**
> Medium risk because it changes when `TOKEN_DETAILS_OPENED` fires by
deferring until market insights and perps market data settle, which can
impact analytics timing/volume. UI behavior is largely unchanged, but
the added async coordination and stale-payload guarding could introduce
missed/duplicated events if incorrect.
> 
> **Overview**
> **Enhances `TOKEN_DETAILS_OPENED` analytics** to include
`has_perps_market` and `severity` (from security data), and refactors
the tracking so it fires only once per token+source.
> 
> Tracking is now **deferred in `TokenDetailsRouteWrapper`** until both
market-insights display resolution and perps market lookup are settled,
with a token-key guard to drop stale market-insights callbacks after
navigation.
> 
> Updates `AssetOverviewContent`’s `onMarketInsightsDisplayResolved`
callback to return `{ isDisplayed, severity }` (instead of a boolean)
and adjusts unit tests accordingly, plus adds an e2e page-object retry
loop for reading the Perps balance value more reliably.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1d0cda9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Prithpal Sooriya
<prithpal.sooriya@users.noreply.github.com>
Co-authored-by: Prithpal Sooriya <prithpal.sooriya@gmail.com>
[af4d7ea](af4d7ea)

Co-authored-by: sahar-fehri <sahar.fehri@consensys.net>
Co-authored-by: Prithpal Sooriya <prithpal.sooriya@users.noreply.github.com>
Co-authored-by: Prithpal Sooriya <prithpal.sooriya@gmail.com>
… it cp-7.73.0 (#28389)

- fix: fix text size when the user increases it cp-7.73.0 (#28340)

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

Before the text and layout were not adjusting when the user increased
the font size in the phone, now it does:

<img height="800" alt="Simulator Screenshot - iPhone 16e - 2026-04-02 at
13 00 56"

src="https://github.com/user-attachments/assets/82507ffc-5098-4d8b-b1d8-cdc438443816"
/>
<img height="800" alt="Simulator Screenshot - iPhone 16e - 2026-04-02 at
13 00 45"

src="https://github.com/user-attachments/assets/71a6ac90-1b9f-4a0a-8cca-45fbe3f17572"
/>
<img height="800" alt="Screenshot 2026-04-02 at 13 00 32"

src="https://github.com/user-attachments/assets/2f32f0f5-2582-4b04-a3e8-2b0c52ab12db"
/>
<img height="800" alt="Simulator Screenshot - iPhone 16e - 2026-04-02 at
13 01 24"

src="https://github.com/user-attachments/assets/5b366e68-6335-4c5a-b0c6-b28b0a5d62ca"
/>


## **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 UI-only layout changes to improve Dynamic Type behavior; main
potential issue is unintended spacing/overlap regressions in the
`SlidingTextCarousel` container across devices and font scales.
> 
> **Overview**
> Improves Market Insights entry card layout under larger system font
sizes.
> 
> `SlidingTextCarousel` no longer relies on a fixed container height; it
now uses an invisible two-line "sizer" `Text` to establish height from
actual font metrics (and pins animated text to `top: 0`) so the rotating
text doesn’t clip/overlap when Dynamic Type scales.
> 
> The footer disclaimer text in `MarketInsightsEntryCard` is also marked
as `shrink` to avoid layout overflow next to the info icon.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
30fb5ef. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[43a952d](43a952d)

Co-authored-by: António Regadas <antonio.regadas@consensys.net>
- chore(deps): bump @xmldom/xmldom to 0.8.12 (#28424)

## **Description**

Bumps `@xmldom/xmldom` from `^0.8.10` to `^0.8.12` to address the
failing production dependency audit (`GHSA-wh4c-j3r5-mjhp`).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Production dependency audit compliance

  Scenario: audit CI passes after xmldom patch update
    Given the repository is on branch chore/fix-audit-xmldom
    When I run yarn audit:ci
    Then no audit suggestions are reported
```

## **Screenshots/Recordings**

### **Before**

N/A (dependency-only change)

### **After**

N/A (dependency-only change)

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **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 dependency-only update; main risk is unexpected behavior
changes in XML parsing due to the transitive library patch bump.
> 
> **Overview**
> Updates the production dependency `@xmldom/xmldom` from
`^0.8.10`/`0.8.11` to `^0.8.12` and refreshes `yarn.lock` to lock the
new resolved version/checksum, addressing the flagged security advisory.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
776772f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[f6dcbae](f6dcbae)

Co-authored-by: George Marshall <george.marshall@consensys.net>
…PredictPayWithAnyTokenInfo cp-7.73.0 (#28416)

- refactor(predict): move deposit amount to PredictPayWithAnyTokenInfo
cp-7.73.0 (#28396)

<!--
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 refactors the deposit amount flow in the Predict
buy-with-any-token feature to improve correctness, reduce redundant
re-computations, and align the token amount update pattern with Perps.

**What changed:**

- **Moved `depositAmount` computation** from `usePredictBuyInfo` into
`PredictPayWithAnyTokenInfo`, co-locating the calculation with the
component that consumes it. This eliminates an unnecessary prop hop and
keeps the headless component self-contained.
- **Gated deposit amount updates on input focus** — deposit amount is
only committed when the user finishes editing (input blur), preventing
redundant effect runs and state churn while the user is actively typing.
- **Removed `isQuotesStale` logic** from `usePredictBuyConditions` —
this workaround for `TransactionPayController` timing gaps is no longer
needed, simplifying the pay fees loading derivation.
- **Added `EngineService.flushState()`** after deposit amount, token
amount, and pay token mutations to ensure immediate state consistency
for the deposit-and-order batch flow.
- **Aligned token amount callback with `amountHuman`** —
`updateTokenAmountCallback` now passes the fiat-converted `amountHuman`
from `useTransactionCustomAmount` instead of the rounded deposit amount,
matching the Perps pattern.

**Files changed (8):**

| File | Change |
| ------------------------------------- |

---------------------------------------------------------------------------------------------
|
| `PredictPayWithAnyTokenInfo.tsx` | Major — owns deposit amount
computation, input focus gating, state flush |
| `PredictPayWithAnyTokenInfo.test.tsx` | Major — new test sections for
computation, gating, dedup behavior |
| `PredictBuyWithAnyToken.tsx` | Minor — passes `currentValue`,
`preview`, `isInputFocused` instead of `depositAmount` |
| `PredictBuyWithAnyToken.test.tsx` | Minor — updated mock interface |
| `usePredictBuyInfo.ts` | Minor — removed `depositAmount` return,
removed `usePredictBalance` and `MINIMUM_BET` imports |
| `usePredictBuyInfo.test.ts` | Minor — removed `depositAmount` tests
and related mocks |
| `usePredictBuyConditions.ts` | Moderate — removed `isQuotesStale`,
simplified `isPayFeesLoading` |
| `usePredictBuyConditions.test.ts` | Moderate — removed `isQuotesStale`
tests and `getNativeTokenAddress` mock |


<!--
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: #28413

## **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]
> **Medium Risk**
> Touches Predict buy payment/deposit amount propagation into the
confirmations flow, including new state-flush behavior; mistakes could
cause incorrect amounts or extra state churn during order placement.
> 
> **Overview**
> Refactors the Predict buy-with-any-token flow so
`PredictPayWithAnyTokenInfo` owns **deposit amount calculation and
propagation** (based on `currentValue`, `preview` fees, and
`usePredictBalance`) and only commits updates when the amount input is
*not focused*.
> 
> Removes `depositAmount` from `usePredictBuyInfo` and updates the
screen/component wiring accordingly;
`updatePendingAmount`/`updateTokenAmount` now de-dupe repeated
emissions, use `amountHuman` for token updates, and call
`EngineService.flushState()` after mutating confirmation/payment state.
> 
> Simplifies pay-fee loading in `usePredictBuyConditions` by dropping
the `isQuotesStale` workaround and associated native-token normalization
logic, with tests updated/expanded to cover the new deposit gating and
rounding behavior.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5526d80. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[11fc440](11fc440)

Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
Sync stable (7.72.0) into release/7.73.0. Resolves conflicts by keeping release versioning (build.gradle, bitrise, pbxproj, package.json, yarn.lock), release Braze notification drawables, release Merkl/Perps/TokenDetails/OAuth E2E paths, stable rampsController tests, and awaited marketing opt-in sync after unlock (keychain upgrade remains onBeforeNavigate).

Made-with: Cursor
## Summary
Merges `stable` (includes 7.72.0 release,
[#27990](#27990)) into
`release/7.73.0`


CHANGELOG entry: null
<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Includes an Android manifest permission-merging change and modifies
the OAuth unlock flow to await a post-unlock marketing-consent sync,
which could affect login latency and Android build/permission behavior
if misconfigured.
> 
> **Overview**
> Pulls in the `7.72.0` release notes into `CHANGELOG.md` and updates
the compare links accordingly.
> 
> Updates Android `AndroidManifest.xml` to de-duplicate
`ACCESS_FINE_LOCATION` declarations during manifest merging (keeping a
single `maxSdkVersion=30` permission and explicitly removing the SDK-23
variant) to avoid Play Store rejections.
> 
> Adjusts `OAuthRehydration` to **await**
`syncMarketingOptInAfterUnlock()` instead of firing it in the background
after a successful unlock.
> 
> Extends ramps selector tests to validate order filtering for selected
account groups across Solana/Bitcoin/Tron addresses, and hardens
network-manager smoke tests by adding
`expectAtLeastTokenSymbolsVisible()` to tolerate variable token list
timing (e.g., `mUSD` loading early).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
eb8a937. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…tion to design system cp-7.73.0 (#28528)

- refactor(onboarding): migrate OAuthRehydration to design system
(#28315)

## **Description**

Migrates the `OAuthRehydration` view from legacy `StyleSheet.create()`,
raw `View`/`Text`, and component-library `Button` to the design system
primitives (`Box`, `Text`, `Button`, `Label` from
`@metamask/design-system-react-native`) with Tailwind CSS via
`useTailwind()`. Also adds theme-aware background color to the
`SafeAreaView`.

### Key changes

- `View` → `Box` with typed layout props (`alignItems`, `gap`,
`paddingHorizontal`)
- `Text` → DS `Text` with `TextVariant` / `TextColor` enums
- `StyleSheet.create()` → `twClassName` and `tw.style()`
- `OldButton (ButtonVariants.Link)` → DS `Button
(ButtonVariant.Tertiary)`
- Added `backgroundColor: colors.background.default` to `SafeAreaView`
for proper theme support
- Removed redundant default props, hoisted `foxImageStyle` to
module-level constant
- Deleted `styles.ts` and `styles.test.ts`
- Extracted render helpers (`renderPasswordField`, `renderHelperText`,
`renderFooterAction`) for cleaner JSX

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: [TO-663](https://consensyssoftware.atlassian.net/browse/TO-663)

## **Manual testing steps**

```gherkin
Feature: OAuth Rehydration Login Screen

  Scenario: Existing social login user unlocks with password
    Given user has an existing social login wallet
    And user is on the OAuth rehydration (password) screen

    When user enters their password
    And taps the Unlock button
    Then the wallet unlocks successfully

  Scenario: Password error is displayed
    Given user is on the OAuth rehydration screen

    When user enters an incorrect password
    And taps the Unlock button
    Then an error message is displayed below the password field

  Scenario: Forgot password flow
    Given user is on the OAuth rehydration screen with an outdated password

    When user taps "Forgot password?"
    Then the delete wallet modal is presented

  Scenario: Other methods navigation
    Given user is on the OAuth rehydration screen (non-outdated password)

    When user taps "Use a different login method"
    Then user is navigated back to the previous screen

  Scenario: Screen uses correct theme background
    Given user is on the OAuth rehydration screen

    When the screen renders in light or dark mode
    Then the background color matches the current theme
```

## **Screenshots/Recordings**

### **Light**

| State | Before | After |
|-------|--------|-------|
| **Empty** | <img width="300" alt="light old empty"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-old-empty.png"
/> | <img width="300" alt="light new empty"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-new-empty.png"
/> |
| **Filled** | <img width="300" alt="light old filled"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-old-filled.png"
/> | <img width="300" alt="light new filled"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-new-filled.png"
/> |
| **Error** | <img width="300" alt="light old error"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-old-error.png"
/> | <img width="300" alt="light new error"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-new-error.png"
/> |
| **Outdated** | <img width="300" alt="light old outdated"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-old-outdated.png"
/> | <img width="300" alt="light new outdated"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/light/oauth-new-outdated.png"
/> |

### **Dark**

| State | Before | After |
|-------|--------|-------|
| **Empty** | <img width="300" alt="dark old empty"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-old-empty.png"
/> | <img width="300" alt="dark new empty"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-new-empty.png"
/> |
| **Filled** | <img width="300" alt="dark old filled"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-old-filled.png"
/> | <img width="300" alt="dark new filled"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-new-filled.png"
/> |
| **Error** | <img width="300" alt="dark old error"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-old-error.png"
/> | <img width="300" alt="dark new error"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-new-error.png"
/> |
| **Outdated** | <img width="300" alt="dark old outdated"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-old-outdated.png"
/> | <img width="300" alt="dark new outdated"

src="https://raw.githubusercontent.com/MetaMask/metamask-mobile/d0de9d7f2744e555a4ff7583b445419ac7692a28/docs/screenshots/oauth-rehydration-pr-28315/dark/oauth-new-outdated.png"
/> |

## **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**
> Mostly a UI/styling refactor, but it touches the OAuth rehydration
login screen layout and input handling, which could impact a critical
unlock flow if rendering/spacing regresses (especially Android status
bar/keyboard behavior).
> 
> **Overview**
> Migrates `OAuthRehydration` from legacy `StyleSheet`/component-library
UI to design-system components (`Box`, `Text`, `Button`, `TextField`)
styled via `useTailwind`, including a theme-aware `SafeAreaView`
background.
> 
> Reworks platform-specific layout behavior by adding Android
`StatusBar.currentHeight` top padding and conditional spacing/keyboard
scroll height, and extracts small render helpers for the password field,
helper text, and footer action.
> 
> Updates tests to match the new DS components and layout (including an
Android-specific spacing/padding assertion), adjusts the password-clear
assertion to check rendered value removal, adds a
`react-native-qrcode-svg` mock, and deletes `styles.ts` plus its unit
test.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c39e3e8. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[0a21a64](0a21a64)

Co-authored-by: TylerC <tyler.chong@consensys.net>
…payment token clear and suppress stale balance alert cp-7.73.0 (#28529)

- fix(predict): reset active order state on payment token clear and
suppress stale balance alert cp-7.73.0 (#28491)

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

Fixes two issues in the Predict buy flow when using the
pay-with-any-token feature:

1. Active order state stuck at pay_with_any_token: When the user had
enough predict balance to cover the bet, resetSelectedPaymentToken()
cleared the payment token via setSelectedPaymentToken(null) but never
transitioned the active order state machine from PAY_WITH_ANY_TOKEN back
to PREVIEW. Fixed by routing through selectPaymentToken(null) instead,
which treats null as a balance token selection and properly transitions
the state.
2. Premature insufficient balance alert while typing: The insufficient
pay token balance alert fired while the user was still editing the
amount, because the deposit amount only syncs to
TransactionPayController when the input loses focus. Gated the alert
behind isInputFocused so it only appears after the user finishes
editing.

Changes
- PredictController.selectPaymentToken — Removed the null early-return
guard; null is now treated as balance token (isBalanceToken = true),
triggering the PAY_WITH_ANY_TOKEN → PREVIEW transition
- usePredictPaymentToken.resetSelectedPaymentToken — Calls
selectPaymentToken(null) instead of setSelectedPaymentToken(null)
- usePredictBuyError — Added isInputFocused param to suppress the
insufficient pay token balance alert while the input is focused
- PredictBuyWithAnyToken — Passes isInputFocused through to
usePredictBuyError
- Updated tests for all changes

<!--
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: #28492
#28493

## **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]
> **Medium Risk**
> Touches the Predict buy flow state machine and error handling; small
but user-facing behavior changes could affect order transitions and when
balance errors are shown.
> 
> **Overview**
> Fixes the Predict *pay-with-any-token* buy flow so clearing the
payment token (passing `null`) is treated as selecting Predict balance,
which also resets the active order from `PAY_WITH_ANY_TOKEN` back to
`PREVIEW`.
> 
> Updates `usePredictPaymentToken.resetSelectedPaymentToken` to route
through `selectPaymentToken(null)` (instead of directly setting state),
and adds an `isInputFocused` gate in `usePredictBuyError` to suppress
the insufficient pay-token balance alert while the amount input is being
edited. Tests were updated to cover the new `null` behavior and the
input-focus suppression.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
75fc16f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[4276cd7](4276cd7)

Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
)

- fix: backfill-consent-event cp-7.73.0 (#28080)

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

Social login (Google / Apple) users who completed onboarding before the
`ANALYTICS_PREFERENCE_SELECTED` event was emitted on the
marketing-consent
screen never had that event fired for them. This PR introduces a
one-time
post-rehydration backfill so those users are counted correctly in
analytics.

**How it works (three-step design kept intentionally pure):**

1. **Migration 131** – runs at startup before the Redux store is live.
If the
persisted state contains a `SeedlessOnboardingController.authConnection`
   value, it writes a
marker into
`onboarding.seedless.pendingSocialLoginMarketingConsentBackfill`.
The migration never fires analytics itself; it only stamps the persisted
   state so the side effect can be done safely after rehydration.

2. **Redux slice** – a new
`SET_PENDING_SOCIAL_LOGIN_MARKETING_CONSENT_BACKFILL`
action/reducer/selector manages the marker in
`state.onboarding.seedless`.

3. **Saga** – `backfillSocialLoginMarketingConsent` runs once inside
`startAppServices` (after `setAppServicesReady`). It reads the marker
from
   the live store, fires `ANALYTICS_PREFERENCE_SELECTED` with
`saveDataRecording: true`, calls `updateDataRecordingFlag`, and clears
the
marker. If the marketing consent is no longer enabled at run time (e.g.
user
toggled it off between migrations) the marker is cleared without sending
any
analytics. If `trackEvent` throws, the marker is left in place so a
future
   run can retry.
## **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: One-time marketing consent analytics backfill for social login users

  Background:
    Given I have a device with a previously installed version of MetaMask Mobile
    And I am a social login (Google or Apple) user
    And I previously accepted marketing data collection during onboarding

  Scenario: backfill event fires once on first launch after upgrade
    Given the app has not yet run migration 129
    And state.security.dataCollectionForMarketing is true
    And state.engine.backgroundState.SeedlessOnboardingController.authConnection is "google"

    When user launches the app and the store rehydrates
    Then migration 129 sets onboarding.seedless.pendingSocialLoginMarketingConsentBackfill to "google"
    And the backfill saga fires an ANALYTICS_PREFERENCE_SELECTED event with has_marketing_consent true
    And the pending marker is cleared to null
    And on subsequent app launches no duplicate event is fired

  Scenario: backfill is skipped when user has opted out of marketing consent
    Given state.security.dataCollectionForMarketing is false
    And state.engine.backgroundState.SeedlessOnboardingController.authConnection is "google"

    When user launches the app and the store rehydrates
    Then migration 129 does NOT set the pending marker
    And no ANALYTICS_PREFERENCE_SELECTED event is fired

  Scenario: stale marker is cleared without analytics when consent is revoked before launch
    Given the pending marker was set in a previous session (e.g. "google")
    And the user has since revoked marketing consent (dataCollectionForMarketing is false)

    When the app launches and the saga runs
    Then the pending marker is cleared to null
    And no ANALYTICS_PREFERENCE_SELECTED event is fired
```

## **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]
> **Medium Risk**
> Adds a new persisted onboarding marker, a state migration, and a
login-triggered saga that sends analytics/updates consent flags;
mistakes could cause missed or duplicate analytics and unexpected
consent state changes after rehydration.
> 
> **Overview**
> Adds a one-time *post-rehydration* analytics backfill for legacy
social login (Google/Apple) users who never emitted
`ANALYTICS_PREFERENCE_SELECTED` for marketing consent.
> 
> This introduces a new onboarding state marker
(`pendingSocialLoginMarketingConsentBackfill`) with
action/reducer/selector support, sets it via new `migration 131` based
on `SeedlessOnboardingController.authConnection`, and runs a new
`backfillSocialLoginMarketingConsentSaga` after `LOGIN` to optionally
query OAuth marketing opt-in, emit the analytics identify/event (with
`saveDataRecording: true`), update recording via
`updateDataRecordingFlag`, then clear the marker and sync
`setDataCollectionForMarketing`.
> 
> Wallet deletion now also clears the marker, and tests were
added/updated across onboarding reducer/selectors, migrations, and
sagas.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2a0bacd. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[505770f](505770f)

Co-authored-by: ieow <4881057+ieow@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**
cherry pick of #28362 
<!--
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]
> **Medium Risk**
> Changes GitHub Actions workflows used for Runway OTA releases, so
misconfiguration could break OTA publishing or route it to the wrong
ref/channel despite being limited to CI config changes.
> 
> **Overview**
> Refactors the Runway OTA path to invoke `push-eas-update.yml` as a
**reusable workflow** (`workflow_call`) instead of dispatching it via
`actions/github-script`, passing the same
PR/base/message/channel/platform inputs.
> 
> Hardens PR-number resolution in `runway-ota-build-core.yml` by
normalizing `gh pr list` results so an empty list doesn’t yield a
literal `null` value.
> 
> Updates `CODEOWNERS` to include the new
`build-and-upload-to-testflight.yml` workflow under
`@MetaMask/mobile-admins`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e4d3e30. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Wei Sun <wei.sun@consensys.net>
Co-authored-by: Cal-L <cal.leung@consensys.net>
<!--
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**
Cherry pick #28368

<!--
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]
> **Medium Risk**
> Changes release automation control flow for OTA updates and production
tag creation; misconfiguration could block or mis-trigger OTA
deployments in CI.
> 
> **Overview**
> Updates `runway-ota-build-core.yml` to invoke the OTA publisher as a
*job-level* reusable workflow (`uses:
./.github/workflows/push-eas-update.yml`) instead of an invalid
step-level call.
> 
> Adds a `validate-ota-pr` gate that hard-fails OTA runs when no PR
number can be resolved, and simplifies production tag creation to use
`decide.outputs.ota_version` directly (removing the prior `release_tag`
output wiring).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
179c16b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Wei Sun <wei.sun@consensys.net>
- chore(ci): clean up workflow inputs and add iOS build number (#28375)

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

The `upload-to-testflight.yml` workflow had opaque `summary_*` prefixed
inputs that made it hard to understand what each value represented. The
`build.yml` workflow also lacked an iOS build number output, forcing
callers to use the Android version code as a proxy.

This PR:
- Renames `summary_*` inputs in `upload-to-testflight.yml` to clearer
names (`build_version`, `build_number`, `build_commit_sha`,
`source_branch`, `build_branch`)
- Adds `ios_version_code` as a new output from `build.yml`, extracted
from the Xcode project's `CURRENT_PROJECT_VERSION`
- Updates all callers (`build-and-upload-to-testflight.yml`,
`runway-ota-build-core.yml`) to use the renamed inputs
- Removes a leftover debug step from `runway-ota-build-core.yml`
- Removes redundant fallback defaults in the upload script call (callers
already provide defaults)

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

N/A — CI workflow changes only. Verify by triggering the
`build-and-upload-to-testflight` or `runway-ota-build-core` workflows
and checking that the step summary displays the correct build metadata
fields.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your 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
- [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 the help of the pr-description AI skill -->

Made with [Cursor](https://cursor.com)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> CI/release workflow wiring changed for TestFlight uploads and build
metadata; mis-mapped inputs or parsing failures could break release
automation even though no app runtime code is touched.
> 
> **Overview**
> Simplifies the reusable `upload-to-testflight.yml` interface by
replacing opaque `summary_*` inputs with explicit `source_branch`,
`build_branch`, `build_commit_sha`, `build_version`, and `build_number`,
and updates the step summary to match.
> 
> Extends `build.yml` to emit an `ios_version_code` output by parsing
Xcode’s `CURRENT_PROJECT_VERSION`, and updates TestFlight callers
(`build-and-upload-to-testflight.yml`, `runway-ota-build-core.yml`) to
pass the new fields and use the iOS build number instead of Android’s.
> 
> Removes a debug step from `runway-ota-build-core.yml` and drops
redundant default fallbacks when invoking
`scripts/upload-to-testflight.sh` (workflow inputs already provide
defaults).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
08245a8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cal-L <cal.leung@consensys.net>
[6334093](6334093)

Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com>
Co-authored-by: Cal-L <cal.leung@consensys.net>
<!--
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**
cherry-pick #28423
<!--
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]
> **Medium Risk**
> Reworks release-candidate build orchestration and notification
plumbing across multiple GitHub Actions workflows; misconfiguration
could cause missing/incorrect RC builds, version bumps, or Slack/PR
announcements.
> 
> **Overview**
> Auto RC builds are refactored to run through the reusable
`runway-ota-build-core.yml`: iOS RC runs first (and performs the version
bump), then Android RC runs with `skip_version_bump`, replacing the
prior inline Bitrise-trigger script approach.
> 
> Adds a reusable `slack-rc-notification.yml` workflow and a new
`scripts/get-build-metadata.sh` to read semver + iOS/Android build
numbers from the checked-out branch; PR comments and Slack messages now
use these values and fall back to linking the GitHub Actions run when no
Android public install URL is available.
> 
> Removes the manual `build-rc-create.yml` workflow, updates Runway RC
workflows to post Slack notifications after success, and adjusts
`build.yml`/metadata emission to rely on the shared build-metadata
script (including ensuring Node is available before reading metadata).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fa89d6b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
cherry pick #28490
<!--
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: changes are limited to the Slack RC notification script’s
environment-variable inputs and payload field naming, with no impact on
app/runtime code. Main risk is missing notifications if CI still sets
legacy vars (`BUILD_NUMBER`/`BITRISE_PIPELINE_URL`).
> 
> **Overview**
> Simplifies `scripts/slack-rc-notification.mjs` to require explicit
`IOS_BUILD_NUMBER`/`ANDROID_BUILD_NUMBER` and a single
`BUILD_PIPELINE_URL`, removing fallbacks to `BUILD_NUMBER` and
`BITRISE_PIPELINE_URL`.
> 
> Cleans up naming by passing `pipelineUrl` through `buildSlackMessage`
(instead of `bitriseUrl`) and updates the script’s env-var documentation
accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4ace38b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
cherry pick #28202
<!--
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]
> **Medium Risk**
> Touches multiple GitHub Actions workflows and release automation
paths; misclassification of OTA vs native hotfix or changelog/tag
mapping could break release/OTA pipelines.
> 
> **Overview**
> Adds explicit **OTA hotfix** support (two-digit patch `X.Y.AB`) across
release automation, including bumping `OTA_VERSION` to `vX.Y.AB` and
generating release PRs without bumping native semver/build versions.
> 
> Introduces `bump-ota-version-constants.sh` and a changelog wrapper
`run-update-release-changelog-mobile.sh` that rewrites Runway OTA
versions into strict SemVer prereleases for `CHANGELOG.md` (and then
fixes comparison URLs back to Runway tags). Also updates OTA bump
detection to parse `OTA_VERSION` by pattern (not fixed line numbers) and
adjusts changelog workflow to run via the new wrapper with explicit
`github-tools` checkout/setup.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6e915d2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Wei Sun <wei.sun@consensys.net>
chloeYue and others added 20 commits April 23, 2026 13:08
# 🚀 v7.73.1 Testing & Release Quality Process

Hi Team,
As part of our new **MetaMask Release Quality Process**, here’s a quick
overview of the key processes, testing strategies, and milestones to
ensure a smooth and high-quality deployment.

---

## 📋 Key Processes

### Testing Strategy
- **Developer Teams:**
Conduct regression and exploratory testing for your functional areas,
including automated and manual tests for critical workflows.
- **QA Team:**
Focus on exploratory testing across the wallet, prioritize high-impact
areas, and triage any Sentry errors found during testing.
- **Customer Success Team:**
Validate new functionalities and provide feedback to support release
monitoring.

### GitHub Signoff
- Each team must **sign off on the Release Candidate (RC)** via GitHub
by the end of the validation timeline (**Tuesday EOD PT**).
- Ensure all tests outlined in the Testing Plan are executed, and any
identified issues are addressed.

### Issue Resolution
- **Resolve all Release Blockers** (Sev0 and Sev1) by **Tuesday EOD
PT**.
- For unresolved blockers, PRs may be reverted, or feature flags
disabled to maintain release quality and timelines.

### Cherry-Picking Criteria
- Only **critical fixes** meeting outlined criteria will be
cherry-picked.
- Developers must ensure these fixes are thoroughly reviewed, tested,
and merged by **Tuesday EOD PT**.

---

## 🗓️ Timeline and Milestones

1. **Today (Friday):** Begin Release Candidate validation.
2. **Tuesday EOD PT:** Finalize RC with all fixes and cherry-picks.
3. **Wednesday:** Buffer day for final checks.
4. **Thursday:** Submit release to app stores and begin rollout to 1% of
users.
5. **Monday:** Scale deployment to 10%.
6. **Tuesday:** Full rollout to 100%.

---

## ✅ Signoff Checklist

Each team is responsible for signing off via GitHub. Use the checkbox
below to track signoff completion:

# Team sign-off checklist
- [ ] Mobile Platform

This process is a major step forward in ensuring release stability and
quality. Let’s stay aligned and make this release a success! 🚀

Feel free to reach out if you have questions or need clarification.

Many thanks in advance

# Reference
- Testing plan sheet -
https://docs.google.com/spreadsheets/d/1tsoodlAlyvEUpkkcNcbZ4PM9HuC9cEM80RZeoVv5OCQ/edit?gid=404070372#gid=404070372
…p-7.72.2 (#29237)

- fix(perps): complete spot-balance parity cp-7.72.2 (#29110)

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

Full fix for **TAT-3016 — [PROD INCIDENT] MetaMask UI shows $0 balance
for accounts with spot + perps funds on HyperLiquid**. Builds on Matt's
stream fix
([#29089](#29089)) and
adds the two missing pieces uncovered during investigation.

### What was broken

For HyperLiquid accounts that hold collateral as spot USDC (non-zero
`spotClearinghouseState.balances.USDC`) but zero perps clearinghouse
balance (`clearinghouseState.withdrawable == 0`,
`marginSummary.accountValue == 0`), three independent code paths were
under-reporting the balance:

| Path | Pre-fix `totalBalance` | Pre-fix `availableBalance` | Why |
|---|---|---|---|
| Streamed (`HyperLiquidSubscriptionService` webData2 +
clearinghouseState callbacks) | `0` | `0` |
`adaptAccountStateFromSDK(data.clearinghouseState, undefined)` never
fetched/attached `spotClearinghouseState` |
| Standalone fetch (`PerpsController.getAccountState({standalone:
true})`) | `0` | `0` | Same omission pattern in a separate provider path
(`HyperLiquidProvider.ts:5545-5573`) |
| Full fetch (`PerpsController.getAccountState()`) | **correct**
(`101.13…`) | `0` | Only path that correctly queried both clearinghouse
+ spot |

### Why it surfaced now

Two independent changes in the week leading up to the incident made a
long-standing omission visible at scale:

1. **`feat(perps): disk-backed cold-start cache for instant data
display`
([#27898](#27898),
merged 2026-04-11)** changed `usePerpsLiveAccount` to seed first render
from the in-memory stream snapshot
(`streamManager.account.getSnapshot()`) before falling back to the
preloaded disk cache. The stream snapshot has always been spot-less
because `HyperLiquidSubscriptionService.ts:1406` and `:1604` have passed
`spotState=undefined` to `adaptAccountStateFromSDK` since December 2025
/ February 2026 (git blame). Flipping the trust order from disk cache →
live stream exposed the pre-existing zero on first paint.
2. **HyperLiquid Portfolio Margin alpha shipped on the 2026-04-18
network upgrade.** PM pushes more users to hold collateral as spot USDC
rather than transferring into perps clearinghouse, expanding the
population hitting the spot-only account shape.

Neither change is the root cause. The fix is on the MetaMask side: the
streamed and standalone account paths must read `spotClearinghouseState`
alongside `clearinghouseState` and include spot balance in
`totalBalance` for parity with the full-fetch path.

### What this PR does

- **Spot-inclusive balance across all three account-state paths.**
Streamed, standalone, and full-fetch paths now fold
`spotClearinghouseState.balances` into `AccountState.totalBalance` via
the shared `addSpotBalanceToAccountState` helper. Only
collateral-eligible coins contribute (`SPOT_COLLATERAL_COINS = {USDC,
USDH}`) — non-collateral spot assets (HYPE, PURR, …) are excluded so
they don't mis-gate the CTA for users who can't actually trade them.
- **USDH handled for HIP-3 USDH DEXs.** The codebase already models USDH
as auto-collateral (`HyperLiquidProvider.#isUsdhCollateralDex` /
`#getSpotUsdhBalance`); including USDH in the allowlist keeps USDH-only
HIP-3 users from hitting the same $0 regression.
- **`Add Funds` CTA gates on `totalBalance`.**
`PerpsMarketDetailsView.showAddFundsCTA` now checks `totalBalance <
threshold && defaultPayToken === null`. "User has any money in the perps
ecosystem → hide Add Funds." Also fixes the pre-existing edge case where
funds locked in an open position incorrectly prompted Add Funds.
- **Order-form preselect keeps `availableBalance`.**
`useDefaultPayWithTokenWhenNoPerpsBalance` gates on withdrawable so
spot-funded / margin-locked accounts still get an external pay token
preselected in `PerpsOrderView`. CTA correctness is preserved by the
component-level `totalBalance` guard.
- **Race-free spot state cache.** `#spotStateGeneration` token +
`#spotStatePromiseUserAddress` tracker in
`HyperLiquidSubscriptionService`. `#ensureSpotState` only shares
in-flight promises when the user matches; `#refreshSpotState` discards
result + error if generation was bumped post-await; `cleanUp` /
`clearAll` bump generation and null promise refs. Prevents user-A's spot
fetch from re-populating the cache after a switch to user B.
- **Cold-start SDK init.** `#refreshSpotState` now awaits
`ensureSubscriptionClient` before `getInfoClient()` (which throws on
fresh instances) so the first `subscribeToAccount` on a cold service
gets the spot-adjusted snapshot instead of perps-only until resubscribe.
- **`NaN` guard** in `addSpotBalanceToAccountState` keeps
`FallbackDataDisplay` sentinels intact when upstream `totalBalance` is
non-numeric.

### What this PR deliberately does NOT change

- **Order-form slider and order-placement warnings**
(`usePerpsOrderForm.ts`, `PerpsOrderView.tsx`) keep reading
`availableBalance`. Those surfaces need *immediately-spendable
withdrawable*. On standard-margin (non-Unified/non-PM) HyperLiquid
accounts, spot USDC is not directly usable as perps margin — users must
transfer spot → perps clearinghouse first. Showing a max order size that
HyperLiquid would reject at submit would be worse UX than the current
behaviour. This is HL's model for standard accounts and outside the
scope of the `$0 balance` incident.
- **No new fields on `AccountState`**. Considered adding
`availableToTradeBalance` (see
[#29090](#29090)) or
`spotUsdcBalance` (see
[#29092](#29092)); both
leak HL primitives into the shared protocol-agnostic contract and will
need reshaping once Portfolio Margin graduates from

[pre-alpha](https://hyperliquid.gitbook.io/hyperliquid-docs/trading/portfolio-margin).
Reusing existing `totalBalance` for the CTA gate solves the incident
with zero contract changes.
- **Portfolio Margin buying-power**. PM pre-alpha uses
HYPE-as-collateral with LTV-based borrow (`token_balance * oracle_price
* ltv`, LTV 0.5 for HYPE, `borrow_cap(USDC) = 1000` per user). Correct
PM buying-power math needs live oracle prices, LTV queries, and
account-mode detection — deferred until PM graduates and the API
stabilises. The spot USDC/USDH fix here still handles PM users who
happen to hold spot collateral.
- **Account-mode UI surface** (standard / Unified / PM). Valuable UX
signal, but independent of the balance math — tracked as a separate
follow-up. The fix on this PR is correct whether or not we surface mode
in the UI.
- **Core-side companion.** Matt's core PR
[#8533](MetaMask/core#8533) covers the stream
fix. The standalone-path fix on this PR needs a 1-liner mirror in
`@metamask/perps-controller` before mobile syncs that package — flagging
as follow-up.

## **Changelog**

CHANGELOG entry: Fixed Perps $0 balance display for accounts funded via
HyperLiquid spot USDC

## **Related issues**

Fixes:
[TAT-3016](https://consensyssoftware.atlassian.net/browse/TAT-3016)

Supersedes:
[#29090](#29090),
[#29092](#29092) (both
introduce a new `AccountState` field; this PR achieves the same
user-visible outcome via `totalBalance` without a contract change)

## **Manual testing steps**

```gherkin
Feature: Perps balance visibility for spot-funded accounts

  Background:
    Given the user holds spot USDC on HyperLiquid mainnet
    And the user's HyperLiquid perps clearinghouse balance (withdrawable, marginSummary.accountValue) is 0
    And the user is on MetaMask mobile with Perps enabled

  Scenario: Header reflects spot-backed collateral
    When user navigates to the Perps tab
    Then the Perps header shows the spot USDC balance (e.g. $101.14), not $0
    And "$0.00 available" is shown as the subtitle (correctly reflecting withdrawable)

  Scenario: Market detail CTA respects total balance
    Given user is on the Perps tab with the spot-only account
    When user opens the BTC market detail view
    Then the Long and Short action buttons are visible
    And the "Add Funds" CTA is not shown

  Scenario: Standalone account-state fetch
    Given a developer queries Engine.context.PerpsController.getAccountState({ standalone: true, userAddress })
    Then totalBalance matches the full-fetch path and includes the spot USDC balance
```

**Agentic recipe**: `evidence/recipe.json` (also in this branch) replays
the scenario via CDP and captures the stream / full-fetch / standalone
values plus screenshots. Run:

```bash
bash scripts/perps/agentic/validate-recipe.sh evidence --no-hud --skip-manual
```

Expected captures (after fix): `{stream,fetch,standalone}_totalBalance =
"101.13506928"` for the `0x316BDE155acd07609872a56Bc32CcfB0B13201fA`
Trading fixture; CTA state `{addFundsVisible:false,
longButtonVisible:true, shortButtonVisible:true}`.

## **Screenshots/Recordings**

Recipe: `evidence/recipe.json` on this branch — captures the 3 balance
paths, screenshots PerpsHome + PerpsMarketDetails, and probes CTA
testIDs on every run.

<table>
  <tr>
    <th width="50%">Before (pre-fix main)</th>
    <th width="50%">After (this PR)</th>
  </tr>
  <tr>
    <td>
      <em>Perps tab header</em><br/>
Shows <code>$0</code> — the streamed value (spot-less). PerpsHome
renders the <code>PerpsEmptyBalance</code> placeholder instead of
Withdraw + Add Funds action buttons.
    </td>
    <td>
      <em>Perps tab header</em><br/>
<img

src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/29110/after-perps-home.png"
width="320"/><br/>
<code>$101.14</code> balance + "$0.00 available" subtitle + Withdraw /
Add Funds row (non-empty funded-state UI)
    </td>
  </tr>
  <tr>
    <td>
      <em>PerpsMarketDetails (BTC)</em><br/>
Shows "Add Funds" CTA instead of Long / Short buttons. Trade path
blocked for spot-only accounts.
    </td>
    <td>
      <em>PerpsMarketDetails (BTC)</em><br/>
<img

src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/29110/after-market-details.png"
width="320"/><br/>
      Long + Short buttons, no "Add Funds" CTA
    </td>
  </tr>
</table>

Visual before-fix screenshot was blocked by intermittent iOS Simulator
crashes during this session (unrelated Apple `libsystem_sim_platform`
issue). Trace-level evidence from the unfixed code stands:

```
// Streamed (HyperLiquidSubscriptionService #cachedAccount replayed via fresh subscribeToAccount listener)
{ "availableBalance": "0", "totalBalance": "0", ... }

// Standalone fetch: getAccountState({ standalone: true, userAddress: '0x316B...' })
{ "availableBalance": "0", "totalBalance": "0", ... }

// Full fetch: getAccountState() — the only path that was correct pre-fix
{ "availableBalance": "0", "totalBalance": "101.13506928", ... }
```

Three paths disagreed on the same account at the same moment. Matt's
`[PerpsDiag][ImportedAccount]` Sentry trace from prod confirms the same
spot-less streamed payload shape for multiple users hitting TAT-3016.

After-fix `trace.json` captures (from `evidence/recipe.json` run on
commit `7f0e9def6f`):

```
stream:     totalBalance = "101.13506928", availableBalance = "0"
fetch:      totalBalance = "101.13506928", availableBalance = "0"
standalone: totalBalance = "101.13506928", availableBalance = "0"
CTA probe:  addFundsVisible = false, longButtonVisible = true, shortButtonVisible = true
```

All three balance paths now agree; CTA probe confirms Long + Short
visible, Add Funds hidden on the BTC market detail view.

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user

SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and

[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance

Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


[TAT-3016]:

https://consensyssoftware.atlassian.net/browse/TAT-3016?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches core perps balance reporting and adds new async spot-state
caching logic, so regressions could impact displayed totals and
streaming updates across accounts/DEXs. Changes are localized and
covered by targeted unit tests, but still affect user-visible
funded-state gating.
> 
> **Overview**
> Fixes HyperLiquid *spot-funded* accounts showing a `$0` perps balance
by folding eligible spot collateral (USDC only) into
`AccountState.totalBalance` across **full fetch, standalone fetch, and
WebSocket-streamed** account updates via new
`getSpotBalance`/`addSpotBalanceToAccountState` helpers.
> 
> Updates `HyperLiquidSubscriptionService` to fetch/cache
`spotClearinghouseState` (with generation-based anti-stale guards) and
apply spot-adjusted totals for both multi-DEX aggregation and single-DEX
`webData2` updates; `HyperLiquidProvider`’s standalone `getAccountState`
path now also fetches spot state and applies the same adjustment.
> 
> Adjusts `PerpsMarketDetailsView` funding CTA logic to key off “has
direct order funding path” (spendable balance above threshold *or*
pay-with-token preselect available), adds coverage for the “total funded
but not spendable/no direct order path” case, and updates a perps market
list page-object selector to tap rows by test id instead of text.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
385c39c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: geositta <matthew.denton@consensys.net>
Co-authored-by: Michal Szorad <michal.szorad@consensys.net>
Co-authored-by: Javier Garcia Vera <javier.vera@consensys.net>
[3e535e6](3e535e6)

[TAT-3016]:
https://consensyssoftware.atlassian.net/browse/TAT-3016?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
Co-authored-by: geositta <matthew.denton@consensys.net>
Co-authored-by: Michal Szorad <michal.szorad@consensys.net>
Co-authored-by: Javier Garcia Vera <javier.vera@consensys.net>
Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com>
…ort cp-7.73.1 (#29256)

- feat(predict): add Polymarket CLOB v2 support cp-7.73.1 (#29076)

## **Description**

This PR implements Polymarket CLOB v2 support for MetaMask Predict (7.74
target), introducing a clean coexistence architecture that keeps v1
working while v2 is toggled on via `predictClobV2`. During the temporary
CLOB host migration window, a companion rollout flag
(`predictClobV2UseLegacyClobHost`) can force v2 traffic onto the legacy
host for internal RC testing without turning v2 on for everyone by
default.

The implementation is designed with deletion in mind — after the v1/v2
coexistence window, v1 can be cleanly removed with minimal surgery. The
work follows the "data-first protocol definition" architecture from the
internal plan: a private `protocol/` module owns all version-specific
differences and is resolved once at the provider entry point.
Lower-level helpers never read feature flags directly.

**Key design decisions:**
- Primary remote flag: `predictClobV2` (default `false`) enables the v2
protocol
- Temporary rollout flag: `predictClobV2UseLegacyClobHost` forces v2 to
use `https://clob-v2.polymarket.com` during the migration window
- Canonical/default v2 host remains `https://clob.polymarket.com`
- Host selection is resolved once into `protocol.transport.clobBaseUrl`;
lower-level helpers never read raw flags
- v2 API key caching is host-aware to avoid reusing credentials across
host changes
- v2 `getBalance()` always returns `Safe USDC.e + Safe pUSD` — no
branching on upgrade state
- Trade path is **relayer-only**, **Permit2-only** fee collection on
pUSD, always runs preflight before submission
- Canonical v2 allowance requirement set defined once; inspector +
compiler are small pure modules
- Deposit/withdraw use **release-time code choices** for preferred vs
fallback variant — not runtime flags
- Wrap: always wraps **entire current Safe USDC.e balance** (never
`MaxUint256`) when maintenance tx is already being emitted
- Unwrap: always unwraps **exact deficit** needed — no over-unwrapping

---

## **Commits**

This PR is now structured as 12 focused commits for easier review:

### 1. `feat(predict): add CLOB v2 feature flag plumbing`
Wires the `predictClobV2` boolean through the Predict feature-flag
infrastructure:
- Adds `predictClobV2Enabled` to `PredictFeatureFlags` interface
- Adds `selectPredictClobV2EnabledFlag` selector
- Extends `resolvePredictFeatureFlags` to resolve the new flag
- Refactors `resolveVersionGatedBooleanFlag` helper to reduce
duplication across the existing flag resolution logic
- Adds selector and resolver tests

### 2. `feat(predict): add CLOB v2 protocol and preflight foundation`
Introduces the two new private modules that everything else builds on:

**`protocol/`** — data-first protocol definitions:
- `definitions.ts`: v1 and v2 `PolymarketProtocolDefinition` objects;
protocol resolution; builder code env config
(`MM_PREDICT_BUILDER_CODE`); deposit/withdraw execution mode types
- `orderCodec.ts`: v2-aware order build, EIP-712 typed data, and relayer
payload serialization
- `transport.ts`: shared CLOB transport helpers parameterized by
protocol endpoint; collapses v1/v2 endpoint differences

**`preflight/`** — private readiness inspection and Safe plan
construction:
- `v2AllowanceRequirements.ts`: canonical declarative list of all 10 v2
allowance requirements (7 ERC-20, 3 ERC-1155)
- `inspectMissingRequirements.ts`: reads on-chain state and returns the
subset of requirements not yet satisfied
- `compileRequirementTransactions.ts`: compiles missing requirements
into `SafeTransaction[]`
- `core.ts`: shared raw-fact readers, wrap/unwrap builders, and signed
Safe execution helpers

All modules covered by unit tests.

### 3. `feat(predict): add CLOB v2 buy and sell flow`
Implements the full v2 trade path inside `PolymarketProvider`:
- `preflight/trade.ts`: `planTradePreflight` + `buildTradeAllowancesTx`
— inspects missing v2 allowances and Safe USDC.e balance; compiles
optional maintenance tx (allowances-only / wrap-only / allowances+wrap /
none)
- `PolymarketProvider`: `placeOrder` now resolves the protocol once,
runs preflight under v2, builds the optional `allowancesTx`, and uses
the protocol's `orderCodec` for order construction, EIP-712 signing, and
relayer payload
- `utils.ts`: adds `encodeWrapUsdceTransaction` and
`encodeUnwrapTransaction` helpers (+ tests)
- v2 preview keeps `feeRateBps = '0'` until the upstream fee endpoint is
confirmed

### 4. `feat(predict): add CLOB v2 deposit flow`
Adds the v2 deposit maintenance planner and wires it into
`PolymarketProvider.prepareDeposit`:
- `preflight/deposit.ts`: `planDepositMaintenance` +
`compileDepositMaintenanceTransactions` — inspects missing v2 allowances
and **pre-existing** Safe USDC.e balance (does not incorporate the
just-entered deposit amount); emits optional maintenance tx
- `PolymarketProvider.prepareDeposit`: under v2, resolves protocol, runs
the maintenance planner, and attaches the optional maintenance tx to the
deposit plan — the 3-step shape (optional deploy → transfer funding
asset → optional maintenance tx) is preserved
- Currently wired to the `usdce-transfer` fallback mode; flip
`depositMode` in the protocol definition to switch to pUSD-native when
that dependency lands

### 5. `feat(predict): add CLOB v2 withdraw flow`
Adds the v2 withdraw planner and wires both the `prepareWithdraw` /
`signWithdraw` contract:
- `preflight/withdraw.ts`: `planWithdraw` — reads missing v2 allowances
and Safe USDC.e balance; computes the exact USDC.e deficit; compiles the
final MultiSend (allowance repair → exact-deficit unwrap-to-Safe →
USDC.e transfer to EOA)
- `PolymarketProvider.signWithdraw`: under v2, parses the requested
amount from the original template calldata, calls `planWithdraw`, and
returns the user-requested amount (not any larger intermediate amount)
- `safe/utils.ts`: adds `parseTransactionCalldata` helper to extract the
withdraw amount from the stored template
- Currently wired to the `usdce-deficit-unwrap` fallback mode; flip
`withdrawMode` in the protocol definition to switch to pUSD-native

### 6. `feat(predict): add CLOB v2 claim flow`
Adds the v2 claim planner and wires it into
`PolymarketProvider.claimWinnings`:
- `preflight/claim.ts`: `planClaim` — reads EOA USDC.e directly (not
Safe balances or provider `getBalance()`); computes `gasStationDeficit =
max(0, MIN_GAS_STATION_USDCE_BALANCE - eoaUsdceBalance)`; proactively
wraps the **entire current Safe USDC.e balance**; compiles the MultiSend
in the required order: (1) missing allowance/operator repair, (2)
wrap-all current Safe USDC.e, (3) claim subcalls, (4) optional
exact-deficit unwrap to EOA
- `PolymarketProvider.claimWinnings`: under v2, resolves protocol and
delegates to `planClaim`; uses protocol-owned claim targets (pUSD as
collateral) rather than per-position collateral metadata

### 7. `test(predict): add CLOB v2 integration coverage`
Adds integration-level tests and reorganizes the provider test suite:
- `preflight/workflows.test.ts`: end-to-end workflow planner tests
covering all four preflight paths (trade, deposit, claim, withdraw) with
concrete on-chain mock scenarios — verifies MultiSend ordering invariant
(approvals first, then wraps/claims/transfers)
- `PolymarketProvider.test.ts`: reorganized into `v1` / `v2` describe
blocks; covers protocol routing (flag off → v1, flag on → v2), v2
`getBalance()` aggregation, all four trade preflight outcomes (none /
allowances-only / wrap-only / allowances+wrap), deposit/withdraw
preferred vs fallback shape, and claim ordering

### 8. `fix: preserve EIP-712 field order in buildProtocolUnsignedOrder`
Fixes the v2 order-signing codec so the generated typed data preserves
the expected field ordering for EIP-712 signing.

### 9. `codex: address PR review feedback (#29076)`
Addresses review feedback in the allowance inspector path:
- forwards `requirement.tokenAddress` into the ERC-1155 operator
approval read instead of relying on a hardcoded contract address
- adds assertions proving the token address is propagated correctly
through the read path

### 10. `refactor(predict): tighten CLOB v2 preflight workflow seams`
Addresses follow-up review feedback without changing behavior:
- makes lower-level transaction compilers private where possible
- keeps `getClaimRequirements` exported for focused pure testing
- tightens `preflight/workflows.test.ts` to assert through planner entry
points instead of private helpers
- renames claim gas-top-up terminology for clarity
(`MIN_GAS_STATION_USDCE_BALANCE_RAW`, `gasStationDeficit`) while keeping
`eoaUsdceBalance` unchanged

### 11. `feat(predict): add configurable CLOB v2 host override`
Adds temporary host-migration plumbing while keeping canonical host
resolution centralized:
- introduces canonical and legacy CLOB host constants
- resolves the selected host into `protocol.transport.clobBaseUrl`
- threads the resolved host through API key creation, order-book reads,
and preview flow
- isolates API key cache entries by protocol + host + address

### 12. `refactor(predict): gate legacy CLOB v2 host with boolean flag`
Simplifies the rollout shape for internal RC testing:
- replaces the nested raw `predictClobV2.clobBaseUrl` rollout control
with a second version-gated boolean flag:
`predictClobV2UseLegacyClobHost`
- keeps the lower-level host plumbing from commit 11 intact
- allows internal RC builds to enable the legacy host remotely while
internal users locally toggle `predictClobV2`

---

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/PRED-817

## **Manual testing steps**

```gherkin
Feature: Polymarket CLOB v2 trading

  Scenario: user trades with CLOB v2 enabled
    Given the predictClobV2 remote flag is enabled
    And the user has an active Polymarket Safe

    When user places a buy or sell order
    Then the provider runs preflight and submits any needed allowance/wrap tx first
    And the order is submitted via the relayer with X-Clob-Version: 2

  Scenario: internal RC uses the legacy v2 CLOB host
    Given the predictClobV2UseLegacyClobHost remote flag is enabled
    And predictClobV2 is enabled via local override

    When user places a buy or sell order
    Then v2 CLOB requests use https://clob-v2.polymarket.com
    And API keys are cached separately from canonical-host credentials

  Scenario: user deposits with CLOB v2 enabled
    Given the predictClobV2 remote flag is enabled

    When user initiates a deposit
    Then the deposit plan includes an optional maintenance tx (allowance repair + wrap pre-existing USDC.e)
    And the newly deposited amount is not included in the wrap

  Scenario: user withdraws with CLOB v2 enabled
    Given the predictClobV2 remote flag is enabled
    And the user requests a specific withdrawal amount

    When user confirms the withdraw
    Then only the exact USDC.e deficit is unwrapped (not all pUSD)
    And the reported amount matches the user-requested amount

  Scenario: user claims winnings with CLOB v2 enabled
    Given the predictClobV2 remote flag is enabled
    And the user has winning positions

    When user claims
    Then all missing v2 allowances are repaired first
    And the entire pre-existing Safe USDC.e is wrapped
    And claim subcalls execute after
    And only the exact EOA gas-top-up deficit is unwrapped to USDC.e

  Scenario: CLOB v2 flag is disabled (v1 behavior)
    Given the predictClobV2 remote flag is disabled

    When user interacts with any predict flow
    Then v1 protocol is used unchanged
```

## **Screenshots/Recordings**

https://www.loom.com/share/155120bd46c44723a8b838172b4fd45b

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user

SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and

[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance

Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> High risk because it changes Polymarket trade/claim/deposit/withdraw
transaction construction and relayer submission paths, including new
Safe preflight logic and EIP-712 signing for a new protocol version.
> 
> **Overview**
> Adds **Polymarket CLOB v2** support behind new Predict feature flags
(`predictClobV2Enabled` plus optional legacy host override), with
host-aware API key caching and endpoint selection.
> 
> Refactors `PolymarketProvider` to resolve a protocol definition once
and route **preview + order submission** through a new `protocol/`
module (v2 uses new order schema/typed data, zero preview fee rate, and
a relayer request header for v2 routing).
> 
> Introduces a `preflight/` layer that inspects on-chain
allowance/approval requirements and builds signed Safe executions for
**trade allowances**, **deposit maintenance**, **claim**, and
**withdraw** (including wrap/unwrap flows and balance aggregation across
USDC.e + pUSD for v2). Adds extensive unit/integration tests and updates
Safe utilities (raw USDC amount decoding, token-address-aware approvals,
Permit2 token selection) plus CI env wiring for
`MM_PREDICT_BUILDER_CODE`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5df04d5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[d9f38f2](d9f38f2)

Co-authored-by: Luis Taniça <matallui@gmail.com>
… spotState ws + tradeable-balance + total-balance math cp-7.72.2 (#29270)

- fix(perps): HL Unified-mode live balance — spotState ws +
tradeable-balance + total-balance math cp-7.72.2 (#29226)

## **Description**

TAT-3016 follow-up covering the remaining HL balance gaps after the
initial spot-balance parity work.

**What's broken on main**

1. `AccountState.totalBalance` is never updated live after a limit order
is placed or cancelled — the HL spot clearinghouse state changes but
nothing reflects it in our streamed cache. The REST `#refreshSpotState`
path only runs on cold-start and standalone fetches, so the cached
snapshot goes stale on every on-chain event (local trade,
external-client trade, funding, liquidation, deposit, transfer).
2. `AccountState.availableToTradeBalance` doesn't exist — order-entry
surfaces read `availableBalance` (= HL `withdrawable`), which is always
`$0` on Unified-mode accounts whose collateral is held as spot USDC.
Users with tradeable balance see the app refuse to open an order.
3. `totalBalance` on the three account-state paths sums
`perps.accountValue + spot.total` without subtracting `spot.hold`. On
Unified/PM the held margin is reported in both fields, so pre-fix
`totalBalance` inflates by the margin amount whenever a limit order is
placed and deflates when cancelled — even though no wealth changed
hands.

**What this PR does**

- Subscribes to HL's `spotState` WebSocket channel alongside the
existing `webData2/3` user-data subscription. Handler updates
`#cachedSpotState`, bumps `#spotStateGeneration` to invalidate any
in-flight REST race, and re-runs `#aggregateAndNotifySubscribers` so UI
consumers see spot-folded totals within one network round-trip of the
change. REST fallback stays for cold-start and the standalone path.
- Adds `AccountState.availableToTradeBalance` as a first-class optional
field: `withdrawable + (spot.total − spot.hold)` for HL,
`availableBalance` trivial default for other providers. Order-entry
surfaces (`PerpsMarketBalanceActions`, `PerpsMarketDetailsView`,
`useDefaultPayWithTokenWhenNoPerpsBalance`, `usePerpsOrderForm`) read
`availableToTradeBalance ?? availableBalance`. Withdraw path
(`PerpsWithdrawView`) keeps reading `availableBalance` unchanged so the
withdraw row never leaks the spot fold.
- Subtracts `spot.hold` from the `totalBalance` sum in both the
single-DEX adapter and the aggregated fold helper. On Standard mode
`spot.hold = 0` so the subtraction is a no-op; on Unified/PM it cancels
the double-count. Result: `totalBalance` no longer ping-pongs on limit
place/cancel, matching HL web.
- Exposes `HyperLiquidProvider.getExchangeClient()` as a non-interface
escape hatch for agentic validation flows that drive HL mutations
directly.
- Adds a `perps-withdraw-available-balance-text` testID to anchor the
non-regression check that withdraw keeps rendering `availableBalance`.
- Adds the latest HL reference docs (`account-abstraction-modes.md`,
`portfolio-margin.md`, `margin-tiers.md`, updated `subscriptions.md` +
`margining.md`) so the code rationale can cite them.

**Follow-ups (not in this PR)**

- Rename `availableBalance → withdrawableBalance` (TAT-3047) — pure
rename against main, kept separate so OTA cherry-picks don't see symbol
drift.
- Agentic regression recipe exercising mode-flip + limit-cycle + REST
parity — tracked separately.

## **Changelog**

CHANGELOG entry: Fixed Perps balance not refreshing after trades,
funding, or transfers for HyperLiquid users, and corrected total balance
inflation on Unified-mode accounts.

## **Related issues**

Fixes:
[TAT-3016](https://consensyssoftware.atlassian.net/browse/TAT-3016)

Supersedes: #29150, #29217 (both closed).

## **Manual testing steps**

```gherkin
Feature: HL spotState live-balance refresh

  Scenario: Spot-funded Unified account sees live balance
    Given the Trading fixture (0x316B…01fA) is connected in Unified mode
    And the Perps screen is open
    Then AccountState.availableToTradeBalance reflects withdrawable + (spot.total − spot.hold)
    And PerpsMarketBalanceActions 'Available' row shows the same value
    And PerpsWithdrawView 'Available Perps balance' row shows $0 (withdrawable only)
    And PerpsOrderView 'Pay with' row defaults to 'Perps balance'

  Scenario: Limit order cycle leaves totalBalance stable
    When the user places a limit order on BTC
    Then AccountState.availableToTradeBalance drops by the reserved margin
    And AccountState.totalBalance is unchanged
    When the user cancels the limit
    Then AccountState.availableToTradeBalance returns to baseline within 5s
    And AccountState.totalBalance is still unchanged

  Scenario: Screenshot parity with HL web
    Then the total shown in the MetaMask Perps header matches app.hyperliquid.xyz (within $0.20)
    And the order-form 'Available' value matches HL 'Available to trade'
```

## **Screenshots/Recordings**

### **Before**

<img width="422" height="865" alt="image"

src="https://github.com/user-attachments/assets/c83cba7e-c70d-442a-9fd3-db0feb7341a0"
/>

### **After**


<img width="412" height="881" alt="image"

src="https://github.com/user-attachments/assets/fd351457-1233-4105-9388-658c527f144e"
/>

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

[TAT-3016]:

https://consensyssoftware.atlassian.net/browse/TAT-3016?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[756b701](756b701)

[TAT-3016]:
https://consensyssoftware.atlassian.net/browse/TAT-3016?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
## **Description**

Merges `stable` into `release/7.73.2` so
[#29233](#29233)
(`release/7.73.2` → `stable`) can merge without conflicts after
[#29107](#29107) landed
on `stable`.

Version strings and native build numbers were kept at **7.73.2** /
**4637** on the release line (`android/app/build.gradle`, `bitrise.yml`,
`ios/MetaMask.xcodeproj/project.pbxproj`). `CHANGELOG.md` includes
updates from `stable`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: #29233

## **Manual testing steps**

```gherkin
Feature: Release branch merge readiness

  Scenario: release/7.73.2 reflects stable after merge
    Given this PR is merged into release/7.73.2
    When viewing PR 29233 (release/7.73.2 to stable)
    Then the branch merges cleanly or shows no merge conflicts
```

## **Screenshots/Recordings**

### **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
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


Made with [Cursor](https://cursor.com)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: documentation-only update to `CHANGELOG.md` with no
functional code changes.
> 
> **Overview**
> Updates `CHANGELOG.md` to include release notes for **7.73.0** and
**7.73.1** (including a fix for Google/Apple login) and adjusts the
compare links so `Unreleased` now starts from `v7.73.1`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
cb70d79. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

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

This PR updates the change log for 7.73.2


## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk documentation-only change: updates `CHANGELOG.md` to include
the `7.73.2` release notes and adjusts compare links; no runtime code is
modified.
> 
> **Overview**
> Adds a new `7.73.2` section to `CHANGELOG.md` documenting Polymarket
CLOB v2 support and fixes for HyperLiquid Perps balance display/refresh
issues.
> 
> Updates the changelog reference links so `[Unreleased]` compares from
`v7.73.2` and adds a `[7.73.2]` compare link.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d55c543. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
# 🚀 v7.73.2 Testing & Release Quality Process

Hi Team,
As part of our new **MetaMask Release Quality Process**, here’s a quick
overview of the key processes, testing strategies, and milestones to
ensure a smooth and high-quality deployment.

---

## 📋 Key Processes

### Testing Strategy
- **Developer Teams:**
Conduct regression and exploratory testing for your functional areas,
including automated and manual tests for critical workflows.
- **QA Team:**
Focus on exploratory testing across the wallet, prioritize high-impact
areas, and triage any Sentry errors found during testing.
- **Customer Success Team:**
Validate new functionalities and provide feedback to support release
monitoring.

### GitHub Signoff
- Each team must **sign off on the Release Candidate (RC)** via GitHub
by the end of the validation timeline (**Tuesday EOD PT**).
- Ensure all tests outlined in the Testing Plan are executed, and any
identified issues are addressed.

### Issue Resolution
- **Resolve all Release Blockers** (Sev0 and Sev1) by **Tuesday EOD
PT**.
- For unresolved blockers, PRs may be reverted, or feature flags
disabled to maintain release quality and timelines.

### Cherry-Picking Criteria
- Only **critical fixes** meeting outlined criteria will be
cherry-picked.
- Developers must ensure these fixes are thoroughly reviewed, tested,
and merged by **Tuesday EOD PT**.

---

## 🗓️ Timeline and Milestones

1. **Today (Friday):** Begin Release Candidate validation.
2. **Tuesday EOD PT:** Finalize RC with all fixes and cherry-picks.
3. **Wednesday:** Buffer day for final checks.
4. **Thursday:** Submit release to app stores and begin rollout to 1% of
users.
5. **Monday:** Scale deployment to 10%.
6. **Tuesday:** Full rollout to 100%.

---

## ✅ Signoff Checklist

Each team is responsible for signing off via GitHub. Use the checkbox
below to track signoff completion:

# Team sign-off checklist
- [ ] Mobile Platform

This process is a major step forward in ensuring release stability and
quality. Let’s stay aligned and make this release a success! 🚀

Feel free to reach out if you have questions or need clarification.

Many thanks in advance

# Reference
- Testing plan sheet -
https://docs.google.com/spreadsheets/d/1tsoodlAlyvEUpkkcNcbZ4PM9HuC9cEM80RZeoVv5OCQ/edit?gid=404070372#gid=404070372
@joaoloureirop joaoloureirop requested review from a team as code owners April 27, 2026 18:58
@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-mobile-platform Mobile Platform team label Apr 27, 2026
@github-actions github-actions Bot added the risk-high Extensive testing required · High bug introduction risk label Apr 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

⏭️ Smart E2E selection skipped - PR targets a release branch (release/*)

All E2E tests pre-selected.

View GitHub Actions results

@joaoloureirop joaoloureirop merged commit 4bbd221 into release/7.74.00 Apr 27, 2026
148 of 155 checks passed
@joaoloureirop joaoloureirop deleted the stable-sync-7.73.2 branch April 27, 2026 19:00
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

risk-high Extensive testing required · High bug introduction risk team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants