[pull] main from MetaMask:main#624
Merged
pull[bot] merged 10 commits intoReality2byte:mainfrom Mar 24, 2026
Merged
Conversation
…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 -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 : )