Skip to content

[pull] main from MetaMask:main#624

Merged
pull[bot] merged 10 commits intoReality2byte:mainfrom
MetaMask:main
Mar 24, 2026
Merged

[pull] main from MetaMask:main#624
pull[bot] merged 10 commits intoReality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 24, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

smgv and others added 10 commits March 24, 2026 06:40
…n flows (#27705)

<!--
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 OAuth rehydration login flow (`OAuthRehydration`) and the underlying
`AuthenticationService` had several related error-handling gaps that
could cause silent failures, misleading Sentry reports, or confusing UI
error messages shown to users:

1. **Non-`Error` rejection values (strings, `null`, `undefined`) were
rethrown as-is** from `unlockWallet`, `fetchSRPs`, and
`rehydrateSeedPhrase`. Because `OAuthRehydration.handleLoginError`
called `loginError.message` without guarding, these bare values could
crash the error handler itself or produce empty/`undefined` messages in
analytics and Sentry.

2. **`handleLoginError` extracted the error message unsafely.** The
original expression `loginError.message || loginError.toString()` fell
back to `loginError.toString()` when `.message` was empty, producing
`"Error: "` — a prefix with no actual content. Calling `.message`
without optional chaining on a non-standard `Error`-like object could
also throw a `TypeError`.

3. **`REHYDRATION_PASSWORD_FAILED` was only tracked when both
`isWrongPasswordError` AND `isComingFromOauthOnboarding` were true**,
but the wrong-password error path (`handlePasswordError`) was always
taken regardless of `isComingFromOauthOnboarding`. The analytic event
was effectively gated incorrectly — a wrong password entered during
non-OAuth rehydration would silently skip both tracking and error
display.

4. **`promptBiometricFailedAlert` was called inside the `trace()` async
callback in `onRehydrateLogin` and `newGlobalPasswordLogin`.** If
`getAuthType()` failed _after_ `unlockWallet` succeeded, the thrown
error escaped the `trace()` callback, was caught by the outer `catch`,
and routed to `handleLoginError` — showing the user a misleading login
failure message even though the wallet was already unlocked.

5. **Non-`Error` values thrown by `onRehydrateLogin` /
`newGlobalPasswordLogin` were cast directly to `Error`** via `loginErr
as Error`, bypassing runtime type checking.


Changes:

- Added `ensureError(error, context)` utility calls at every `throw`
site in `unlockWallet`, `fetchSRPs`, and `rehydrateSeedPhrase`. This
converts any non-`Error` rejection (string, `null`, `undefined`) into a
proper `Error` instance with a non-empty message, preserving the
original `Error` when it already has a message.
  - `unlockWallet` → `ensureError(error, 'Unlock wallet failed')`
  - `fetchSRPs` → `ensureError(error, 'Fetch SRPs failed')`
- `rehydrateSeedPhrase` → `ensureError(error, 'Rehydrate seed phrase
failed')`
  
- **`promptBiometricFailedAlert`** — wrapped the `getAuthType()` call in
a try/catch and rethrows via `ensureError` so the thrown value is always
a proper `Error`.
 
- **`onRehydrateLogin` and `newGlobalPasswordLogin`** — moved
`promptBiometricFailedAlert()` _outside_ the `trace()` callback and
wrapped it in its own try/catch that logs and swallows the error. A
failure to show the biometric alert after a successful unlock is a
best-effort UX concern and must not be misreported as a login failure.

- **`handleLoginError`** — replaced the unsafe `loginError.message ||
loginError.toString()` expression with `loginError.message?.trim() ||
loginError.name?.trim() || String(loginError)`:
- Optional chaining prevents `TypeError` when `.message` or `.name` is
`undefined` on non-standard error objects.
  - `.trim()` guards against whitespace-only messages.
- `String(loginError)` is the final fallback — always produces a
non-empty string.
 
- **Wrong-password error handling** — restructured the
`isWrongPasswordError` block so that `REHYDRATION_PASSWORD_FAILED` is
conditionally tracked (only when `isComingFromOauthOnboarding`) and
`handlePasswordError` is always called for any wrong-password error
regardless of OAuth origin.

- **Catch blocks** — replaced `loginErr as Error` casts with a proper
runtime check: `loginErr instanceof Error ? loginErr : new
Error(String(loginErr))`.


Jira Link: https://consensyssoftware.atlassian.net/browse/TO-603

## **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: ensure error messages are never empty in authentication
and login flows

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: OAuth rehydration login error handling

  Scenario: user enters wrong password during OAuth rehydration
    Given the app is on the OAuth rehydration screen
    And the user has a social login account

    When the user enters an incorrect password and taps login
    Then the wrong password error message is displayed
    And the REHYDRATION_PASSWORD_FAILED analytic event is tracked (only for OAuth onboarding)

  Scenario: biometric alert fails after successful wallet unlock
    Given the app is on the OAuth rehydration screen
    And the device has biometrics configured
    And getAuthType() is mocked to fail after unlock succeeds

    When the user logs in successfully
    Then the wallet is unlocked
    And no login error is displayed to the user
    And the biometric alert failure is silently logged

  Scenario: native module rejects with a non-Error value during unlock
    Given the app is on the OAuth rehydration screen

    When a third-party native module rejects with null or a plain string
    Then the error is converted to a proper Error instance
    And a meaningful error message is shown to the user
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches `unlockWallet`/seedless rehydration error propagation and the
OAuth rehydration login path; mistakes could change user-visible login
failures or analytics/Sentry reporting, but the changes are localized
and well-covered by new tests.
> 
> **Overview**
> Prevents empty or non-standard errors from leaking through
authentication by consistently wrapping thrown/rejected values with
`ensureError` in `Authentication.unlockWallet`, seedless `fetchSRPs`,
and `rehydrateSeedPhrase`.
> 
> Hardens `OAuthRehydration` error handling by extracting a non-empty
message via `message.trim()`/`name`/`String(error)`, using `ensureError`
in catch blocks, and ensuring wrong-password handling always shows the
invalid-password UI while only tracking `REHYDRATION_PASSWORD_FAILED`
for the OAuth onboarding flow.
> 
> Moves `promptBiometricFailedAlert` to a **best-effort** post-unlock
step (and logs failures instead of treating them as login failures), and
adds/updates extensive unit coverage around these
error/analytics/biometric edge cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
20bfc67. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**
Add Stable network (chain ID 988 / 0x3dc) logo and native token (USDT0)
icon to MetaMask Mobile. This enables the network logo and native token
icon to display correctly when users
add or interact with the Stable network.
## **Changelog**
                              
CHANGELOG entry: Added Stable network logo and USDT0 native token icon

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Stable network logo display

Scenario: user adds Stable network and sees correct logos
Given the app is open on the wallet screen

When user adds Stable network (chain ID 988) via Settings > Networks > Add Network
Then the Stable network logo is displayed in the network selector
And the native token USDT0 shows the correct icon on the token list
````

Screenshots/Recordings

Before



After

<img width="1206" height="2622" alt="Simulator Screenshot - iPhone 17
Pro - 2026-03-18 at 13 32 39"
src="https://github.com/user-attachments/assets/d097d177-58f1-418c-a36c-90688aa15d68"
/>
<img width="1206" height="2622" alt="Simulator Screenshot - iPhone 17
Pro - 2026-03-18 at 13 30 21"
src="https://github.com/user-attachments/assets/8ef98ad6-3a1e-4f8d-8d01-2e5df65b3959"
/>


Pre-merge author checklist

- [x] I've followed https://github.com/MetaMask/contributor-docs and
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 https://jsdoc.app/ format if
applicable
- [x] I've applied the right labels on the PR (see
https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md).
Not required for external
contributors.

Pre-merge reviewer checklist

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are limited to adding static image assets and wiring
them into existing icon/chainId mappings, with no transaction/auth or
RPC logic changes.
> 
> **Overview**
> Adds Stable network icon support by introducing `STABLE_MAINNET`
(`0x3dc`) in `customNetworks.tsx` and mapping it in
`CustomNetworkImgMapping` to `stable.png`.
> 
> Updates `image-icons.js` to include a `STABLE` logo and a `USDT0`
native token icon (`stable-native`), and adds the corresponding
`stable-native.svg` asset.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0ab9c9c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…#27798)

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

- **`NftGridItemBottomSheet.tsx`** *(new)* — Design-system bottom sheet
replacing the native `ActionSheet`, with the same "Refresh metadata /
Remove / Cancel" actions. Follows the identical state-driven visibility
pattern as `RemoveTokenBottomSheet`.
- **`NftGrid.tsx`** — Swapped `NftGridItemActionSheet` +
`actionSheetRef` + `useEffect` for the new `NftGridItemBottomSheet`
driven by `longPressedCollectible !== null`.
- **`NFTsSection.tsx`** — Homepage NFT section now wires long-press to
open the bottom sheet (was previously a `noop`).
- **`RemoveTokenBottomSheet.tsx`** — Migrated the deprecated
`BottomSheetHeader` import from the component-library to
`@metamask/design-system-react-native`.

## **Changelog**

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

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

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

CHANGELOG entry: updated NFT long-press actions to use a bottom sheet
consistent with the token list experience

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-2958 &
https://consensyssoftware.atlassian.net/browse/ASSETS-2971

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


https://github.com/user-attachments/assets/e28c895f-ed97-4f04-89e3-bc2859b6c2b6


<!-- [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**
> Moderate UI refactor that changes the long-press interaction path for
NFT actions and adds controller calls behind new bottom-sheet handlers;
regressions would mainly impact NFT refresh/remove flows.
> 
> **Overview**
> Replaces the native `ActionSheet`-based NFT long-press menu with a
design-system `NftGridItemBottomSheet`, driven by state (`isVisible` +
`onClose`) instead of an imperative ref.
> 
> Enables long-press actions in both `NftGrid` and the homepage
`NFTsSection` (previously a no-op on homepage), and adds/updates tests
to assert the bottom sheet opens and that refresh/remove invoke
`NftController.addNft` / `removeAndIgnoreNft` with the resolved
`networkClientId`.
> 
> Aligns token removal UI by switching `RemoveTokenBottomSheet` to use
`BottomSheetHeader` from `@metamask/design-system-react-native`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bdc48bd. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

> Updates the `LoginScreen` WDIO page object to use Appwright
`getElementByID` for the login container when running with a device,
aligning element lookup with test IDs.
> 
> Refines password field lookup in `getPasswordInputElement` by
switching Android to the more flexible `getElementByCatchAll` and
removing the iOS-specific fallback to a generic `textfield`, instead
targeting `LoginViewSelectors.PASSWORD_INPUT` directly.
> 

## **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 test-only change that updates element lookup strategies; main
risk is flaky or broken login E2E tests if the new IDs/catch-all
matching don’t resolve consistently across platforms.
> 
> **Overview**
> Updates the WDIO `LoginScreen` page object to use Appwright
`getElementByID` for the login container when a device is present,
instead of using the resource-id based lookup.
> 
> Refines `getPasswordInputElement` to use `getElementByCatchAll` on
Android and removes the iOS fallback to a generic `textfield`,
consistently targeting `LoginViewSelectors.PASSWORD_INPUT` via
Appwright.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7681d1d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…27404)

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

Hides the **Speed up** and **Cancel** actions in the activity list and
in transaction details when the user has chosen a non‑native token to
pay for gas (`selectedGasFeeToken`), because those flows are not
supported for gas‑fee‑token transactions.

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

## **Changelog**

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

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

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

CHANGELOG entry: Added check to hide Speed up and Cancel buttons in the
activity list and transaction details when the user has selected another
token to pay for gas

## **Related issues**

Fixes: MetaMask/mobile-planning#2424

## **Manual testing steps**

```gherkin
Feature: Hide Speed up and Cancel when gas is paid with alternate token

  Scenario: User does not see Speed up and Cancel for a pending transaction paid with alternate token
    Given the user has created a transaction
    And the user has chosen a non-native token in the gas/token selector to pay for gas
    And the transaction has been submitted and is pending

    When the user opens the activity list
    And the user locates that pending transaction

    Then the Speed up button is not displayed for that transaction
    And the Cancel button is not displayed for that transaction

  Scenario: User sees Speed up and Cancel for a pending transaction paid with native token
    Given the user has created a transaction
    And the user has not selected a different token for gas (native token is used)
    And the transaction has been submitted and is pending

    When the user opens the activity list
    And the user locates that pending transaction

    Then the Speed up button is displayed for that transaction
    And the Cancel button is displayed for that transaction

  Scenario: User does not see Speed up and Cancel in transaction details when gas was paid with alternate token
    Given the user has a pending transaction paid with a non-native gas token
    And the user is viewing the activity list

    When the user opens the details of that pending transaction

    Then the Speed up button is not displayed in the transaction details
    And the Cancel button is not displayed in the transaction details
```

## **Screenshots/Recordings**


[gasless.webm](https://github.com/user-attachments/assets/cf134ab5-9943-4967-81d2-9073d101c990)


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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-logic change that only gates rendering of existing actions
based on `selectedGasFeeToken`, with unit tests added to prevent
regressions.
> 
> **Overview**
> Hides **Speed up** and **Cancel** actions for pending/approved
transactions when `selectedGasFeeToken` is set (i.e., gas is paid with a
non-native token) in both the activity list (`TransactionElement`) and
the transaction details sheet (`TransactionDetails`).
> 
> Adds a shared utility `hasGasFeeTokenSelected` in
`confirmations/utils/transaction` and extends test coverage to assert
the buttons are suppressed when a gas fee token is selected (and still
shown otherwise).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c323793. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
This pr patch the expo-web-browser to support https redirect schema
Taking reference from expo-web-browser sdk 55

https://github.com/expo/expo/blob/308031a6665f885811760aff7aebb68aea4a846a/packages/expo-web-browser/ios/WebAuthSession.swift#L36

<!--
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: expo-web-browser support https redirect scheme 
CHANGELOG entry: use webcredential for ios google login 

## **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**
> Moderate risk because it changes iOS `ASWebAuthenticationSession`
callback configuration and entitlements, which can affect login/redirect
flows and associated-domain behavior.
> 
> **Overview**
> Enables **HTTPS redirect-based auth callbacks** on iOS by patching
`expo-web-browser`’s `WebAuthSession` to use iOS 17.4+/macOS 14.4+
`.https(host:path)` callbacks when the `redirectUrl` is `https`, falling
back to the legacy `callbackURLScheme` behavior otherwise.
> 
> Updates iOS entitlements (`MetaMask.entitlements` and
`MetaMaskDebug.entitlements`) to include
`webcredentials:link.metamask.io`, and wires the patch into the build
via a Yarn `resolutions` entry plus corresponding `yarn.lock` changes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7730be3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…27836)

## Summary

- Introduces `tests/helpers/swap/smart-transactions-mocks.ts` — a
reusable helper that mocks the STX backend (`/getFees`,
`/submitTransactions`, `/batchStatus`, `/getTxStatus`) and forwards
signed transactions to Anvil so they get mined and receipts resolve
correctly.
- Removes `.withDisabledSmartTransactions()` from all affected test
fixtures so tests run with the same STX-enabled configuration as
production.
- Applies the new helper to all swap/bridge regression and smoke specs:
`swap-action-regression`, `swap-token-chart`, `swap-token-rwa`,
`swap-action-smoke`, and `bridge-action-smoke`.

## How Smart Transactions work in tests

When STX is enabled the swap publish hook intercepts the transaction
before broadcast:

1. Calls `POST /getFees` → mock returns a static fee schedule so the
controller can sign the tx locally.
2. Signs the tx locally and calls `POST /submitTransactions` → mock
**forwards all `rawTxs` to Anvil** via `eth_sendRawTransaction`
(sequentially, preserving nonce order for approval + swap batches), then
returns a UUID.
3. Because `mobileReturnTxHashAsap: true` the hook resolves immediately
with the locally-computed `txHash` — no polling needed.
4. `TransactionController` polls Anvil for `eth_getTransactionReceipt`
using that hash → Anvil returns a valid receipt → tx is marked
**Confirmed**.

### Key fix: ERC-20 → ETH batch submissions

Previously the mock only forwarded `rawTxs[0]` (the approval tx) to
Anvil. The swap tx (`rawTxs[1]`) was never mined, so
`TransactionController` never found a receipt and the swap stayed
**Pending**. The fix loops over all entries in `rawTxs` and forwards
each one sequentially.

## Modified scripts

- [x] `swap-action-regression` — ETH→WETH and WETH→ETH swaps confirm
end-to-end
- [x] `swap-token-chart` — ETH→DAI swap from token chart confirms
- [x] `swap-token-rwa` — USDC→GOOGLON swap (CowSwap intent flow)
- [x] `swap-action-smoke` — ETH→USDC and USDC→ETH swaps confirm
- [x] `bridge-action-smoke` — ETH (Mainnet)→ETH (Base) bridge confirms

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk since changes are isolated to E2E test harnesses/mocks; main
risk is increased flakiness if STX mock assumptions (fee schema, proxy
matching, Anvil forwarding) diverge from app behavior.
> 
> **Overview**
> **Swap/bridge E2E tests now run with Smart Transactions enabled** by
removing `.withDisabledSmartTransactions()` from affected fixtures.
> 
> Adds `setupSmartTransactionsMocks` to mock the STX backend
(`/getFees`, `/submitTransactions`, `/batchStatus`, and a low-priority
`/getTxStatus` fallback) and, crucially, forwards all submitted `rawTxs`
sequentially to Anvil via `eth_sendRawTransaction` so batched
approval+swap flows get mined and receipts resolve.
> 
> Updates swap and bridge regression/smoke specs to wrap existing
`testSpecificMock` with the new STX mocks (and bumps timeouts where
needed).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8082888. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

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

## **Description**
 Add commas to PnL

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

## **Changelog**

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

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

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

CHANGELOG entry: add commas to PnL

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-2966

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**
<img width="441" height="883" alt="image"
src="https://github.com/user-attachments/assets/88f816c2-e54e-4977-8733-10d1e6cb201a"
/>

<!-- [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 change to how the price difference (PnL) value is
formatted and signed in `AssetOverview`.
> 
> **Overview**
> Improves the `AssetOverview` price-diff (PnL) label formatting by
switching from `addCurrencySymbol(diff, ...)` to
`formatPriceWithSubscriptNotation(Math.abs(diff), ...)`, which adds
thousands separators and consistent small-value formatting.
> 
> Also fixes sign rendering so negative diffs show a leading `-`
(positive keeps `+`, zero shows no sign) while keeping the percentage
calculation display unchanged.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
4055c10. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
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: https://consensyssoftware.atlassian.net/browse/MUL-1532

## **Manual testing steps**

no manual testing steps

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Removes multiple implicit `HardwareWalletType.Ledger` fallbacks across
connection/error flows, which can change runtime behavior when
`walletType` is unset and may surface new error/visibility paths. Risk
is moderated by added unit tests but touches core hardware-wallet
connection state handling.
> 
> **Overview**
> Eliminates silent defaulting to `HardwareWalletType.Ledger` when
`walletType` is `null/undefined`, propagating `null` through error
creation/parsing and transport/device-discovery handlers instead.
> 
> Updates the connection flow to **require an explicit wallet type**:
`ensureDeviceReady` now throws if neither `walletType` nor
`targetWalletTypeRef` is available, and the hardware wallet bottom sheet
**won’t render** unless `walletType` is set (even in active connection
states). Adds targeted tests covering the new null-walletType behavior
and edge cases (including null adapter/walletType error handling).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
96479ae. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
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 adds Solana delegation support for MetaMask Card spending limits
and updates the UI to reflect multi-network support.

**Key changes:**

1. **Solana Delegation Support**: Implements the complete delegation
flow for Solana tokens, enabling users to set spending limits on Solana
assets (e.g., SOL, USDC on Solana).
- Added `completeSolanaDelegation` method in CardSDK for the
Solana-specific backend endpoint
- Integrated Solana Wallet Snap for message signing (`signCardMessage`)
and SPL Token approval transactions (`approveCardAmount`)
- Updated `useCardDelegation` hook to handle both EVM and Solana chains

2. **UI Updates**:
- Updated the "Other" button in the Spending Limit screen to display
Base and Solana network icons alongside the three dots icon
- Removed "Solana not supported" warnings and filters from
AssetSelectionBottomSheet and SpendingLimit components
- Enabled the "Manage Spending Limit" option for all supported networks
including Solana

## **Changelog**

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

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

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

CHANGELOG entry: Added Solana delegation support for MetaMask Card
spending limits

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Solana Delegation for Card Spending Limits

  Scenario: User sets spending limit on Solana token
    Given user is authenticated with MetaMask Card
    And user has a Solana account with SOL or USDC balance

    When user navigates to Spending Limit screen
    And user selects a Solana token (SOL or USDC)
    And user chooses "Full access" or sets a custom spending limit
    And user confirms the spending limit

    Then user is prompted to sign a message via Solana Wallet Snap
    And user approves the SPL Token approval transaction
    And spending limit is successfully set for the Solana token

  Scenario: User views "Other" networks button
    Given user is on the Spending Limit screen

    When user views the asset selection cards

    Then the "Other" button displays Base and Solana network icons with a three dots icon
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Adds a new Solana signing + SPL approval flow via the Solana Wallet
Snap and changes delegation completion API routing/validation, touching
transaction execution and auth-sensitive logic. Bugs here could break
spending-limit updates or cause incorrect on-chain approvals across
networks.
> 
> **Overview**
> Adds **Solana support for card spending-limit delegation** end-to-end:
`useCardDelegation` can now sign SIWE-style messages via the Solana
Wallet Snap, submit an SPL token approval (`approveCardAmount`), wait
for non-EVM confirmation via
`MultichainTransactionsController:stateChange`, then complete delegation
via the backend.
> 
> Updates the SDK to replace `completeEVMDelegation` with network-aware
`completeDelegation` (EVM vs Solana endpoints + format validation), and
removes prior Solana gating across the UI (spending-limit screen
validation/warnings, asset-selection filtering/footer, and Card Home
manage-limit availability). Also refreshes the “Other” asset card to
show Base+Solana network icons and bumps `@metamask/solana-wallet-snap`
to `^2.7.4`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
11f71a5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Mar 24, 2026
@pull pull Bot added the ⤵️ pull label Mar 24, 2026
@pull pull Bot merged commit 4371caf into Reality2byte:main Mar 24, 2026
3 of 13 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants