Skip to content

[pull] main from MetaMask:main#331

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

[pull] main from MetaMask:main#331
pull[bot] merged 6 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull

@pull pull Bot commented Nov 17, 2025

Copy link
Copy Markdown

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

wachunei and others added 6 commits November 17, 2025 17:42
<!--
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 pull request updates the ramp navigation logic to add an additional
check before routing users to the unified deposit flow. Now, the unified
ramp is only used when the user is depositing or the ramp type is set to
"BUY", providing more granular control over navigation.

Navigation logic improvements:

* Updated the condition in `useRampNavigation` (in
`useRampNavigation.ts`) to only route to the unified deposit flow if the
mode is `DEPOSIT` or the `rampType` is `BUY`, in addition to the
existing feature flag and override checks.

## **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/TRAM-2844

## **Manual testing steps**

```gherkin
Feature: Sell

  Scenario: user opens Sell
    Given unified flag v1 flag is on

    When user clicks on sell
    Then sell is opened
    And not deposit
```

## **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]
> Updates ramp navigation to use unified V1 only for DEPOSIT or BUY;
SELL now always routes to the aggregator, with tests revised
accordingly.
> 
> - **Ramp navigation logic (`useRampNavigation.ts`)**:
> - Apply unified V1 routing only when `mode` is `DEPOSIT` or aggregator
`rampType` is `BUY` (defaults to BUY when absent).
> - Route `SELL` directly to aggregator, bypassing unified deposit flow.
> - **Tests (`useRampNavigation.test.ts`)**:
> - Update assertions to check direct `navigation.navigate` calls
(including nested params) instead of mocking route utils.
> - Add/refine cases for unified routing decisions: DEPOSIT vs
AGGREGATOR, BUY vs SELL, intent propagation, and
`overrideUnifiedBuyFlag` behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9b1b825. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: AxelGes <axelges9@gmail.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**

Creates a reusable `onChainAnalyticProperties` util to avoid code
duplication. This util is used in four components to extract the
`chain_id` for analytics events for notifications of type `on-chain`.

Also adds a test file for the new util.

test(notifications): update tests for onChainAnalyticProperties

Updates the tests for the `onChainAnalyticProperties` util to follow the
project's conventions:
- Renames the tests to not start with "should".
- Replaces `.toEqual` with `.toStrictEqual`.

<!--
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: N/A

## **Manual testing steps**

N/A

## **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]
> Introduces a reusable `onChainAnalyticProperties` helper and replaces
duplicated analytics property logic in notification components; adds
unit tests.
> 
> - **Notifications analytics**:
> - Centralize on-chain analytics extraction via
`util/notifications/methods/notification-analytics.ts`
(`onChainAnalyticProperties`).
>   - Replace inline `chain_id` derivation in:
>     - `components/UI/Notification/List/index.tsx`
> - `components/Views/Notifications/Details/Fields/NetworkFeeField.tsx`
> - `components/Views/Notifications/Details/Fields/TransactionField.tsx`
> -
`components/Views/Notifications/Details/Footers/BlockExplorerFooter.tsx`
> - **Tests**:
> - Add unit tests for `onChainAnalyticProperties` in
`util/notifications/methods/notification-analytics.test.ts`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f3bfae2. 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.
Here is the PR to fix it
MetaMask/github-tools#156.
-->

## **Description**

Fix the error discussed in slack here:
https://consensys.slack.com/archives/C09B64PEHAQ/p1763403469760889
Discussion in MM Extension for same issue:
https://consensys.slack.com/archives/C09B64PEHAQ/p1761903353525079

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

## **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]
> Updates the release PR workflow to use a newer MetaMask/github-tools
ref and aligns the github-tools-version input.
> 
> - **CI**
> - Update `MetaMask/github-tools` reusable workflow ref in
`.github/workflows/create-release-pr.yml` to
`6a04e4d0c8c25680a7543cfcd2e2fb7125b6759c`.
>   - Align `with.github-tools-version` to the same ref.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8c79719. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This pull request updates the `BuildQuote` view in the Ramp Aggregator
to support and properly handle a new `intent` parameter (of type
`RampIntent`) in navigation params. It ensures that the intent is set in
the SDK when the view is mounted, and updates tests and snapshots
accordingly. Additionally, it makes minor improvements to UI test
identifiers and cleans up related code.

**Ramp Intent Handling:**
- Refactored the `BuildQuote` view to extract `intent` from navigation
params and ensure it is passed to the SDK via `setIntent` on mount,
using a new `intentHandled` state to prevent repeated calls.
[[1]](diffhunk://#diff-8f431ed27f208e5f873f504bd846413111f1b8554ff5e60d1fb34080fa569b4eL109-R109)
[[2]](diffhunk://#diff-8f431ed27f208e5f873f504bd846413111f1b8554ff5e60d1fb34080fa569b4eL118-R118)
[[3]](diffhunk://#diff-8f431ed27f208e5f873f504bd846413111f1b8554ff5e60d1fb34080fa569b4eR128)
[[4]](diffhunk://#diff-8f431ed27f208e5f873f504bd846413111f1b8554ff5e60d1fb34080fa569b4eR150-R159)
- Updated the `BuildQuoteParams` interface to extend `RampIntent`,
allowing the view to receive intent-related data directly.
- Updated tests to mock and verify the new intent handling logic,
including a new test to ensure `setIntent` is called when intent params
are present.
[[1]](diffhunk://#diff-65a8de4d5905fd0ee2ecb35e83684172ea625155e9c957192d88670847637a41R91)
[[2]](diffhunk://#diff-65a8de4d5905fd0ee2ecb35e83684172ea625155e9c957192d88670847637a41R251)
[[3]](diffhunk://#diff-65a8de4d5905fd0ee2ecb35e83684172ea625155e9c957192d88670847637a41L263-R270)
[[4]](diffhunk://#diff-65a8de4d5905fd0ee2ecb35e83684172ea625155e9c957192d88670847637a41R436-R445)

**UI and Test Improvements:**
- Changed the configuration menu button's `testID` from `"button-icon"`
to `"deposit-configuration-menu-button"` and updated the icon from
`"ArrowLeft"` to `"Setting"` in test snapshots for clarity and
consistency.
[[1]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L182-R186)
[[2]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L3041-R3045)
[[3]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L4561-R4468)
[[4]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L5321-R5228)
[[5]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L7884-R7791)
[[6]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L8644-R8551)
[[7]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L11116-R11023)
- Adjusted various handler tags and removed redundant view structures in
test snapshots to reflect the UI updates.
[[1]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L450-R450)
[[2]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L3309-R3309)
[[3]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L3727-L3825)
[[4]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L4069-R3972)
[[5]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L4829-R4732)
[[6]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L5589-R5492)
[[7]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L8152-R8055)
[[8]](diffhunk://#diff-b7f34e07bf901a0928396a118a42a13071e38f0830b470c8ec9c76eb73894df4L8912-R8815)

**Other Minor Fixes:**
- Ensured the `showBack` parameter defaults to `false` when not
provided, for more predictable navigation behavior.
[[1]](diffhunk://#diff-8f431ed27f208e5f873f504bd846413111f1b8554ff5e60d1fb34080fa569b4eL433-R442)
[[2]](diffhunk://#diff-8f431ed27f208e5f873f504bd846413111f1b8554ff5e60d1fb34080fa569b4eL445-R454)
- Imported `RampIntent` type where necessary to support the new params
structure.
[[1]](diffhunk://#diff-65a8de4d5905fd0ee2ecb35e83684172ea625155e9c957192d88670847637a41R33)
[[2]](diffhunk://#diff-8f431ed27f208e5f873f504bd846413111f1b8554ff5e60d1fb34080fa569b4eL73-R73)

## **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: Removed Splash screens from Deposit/Buy/Sell

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-2838

## **Manual testing steps**

```gherkin
Feature: Buy/Sell

  Scenario: user opens Buy/Sell
    Given a new user

    When user opens buy or sell
    Then don't see a get started screen

Feature: Depoist

  Scenario: user opens Deposit
    Given a new user

    When user opens deposit
    Then don't see a get started screen
```

## **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]
> Removes Buy/Sell/Deposit splash screens, starts flows at
`BUILD_QUOTE`, adds `RampIntent` handling in `BuildQuote`, and updates
routing/SDK/tests accordingly.
> 
> - **Aggregator (Buy/Sell)**
> - `BuildQuote`: accepts `RampIntent` via params, calls `setIntent` on
mount; memoizes intent; defaults `showBack` to `false`.
> - Routing: initial route set to `Routes.RAMP.BUILD_QUOTE`; parent
stack uses `Routes.RAMP.ID`; deeplinks/utils navigate to `ID ->
BUILD_QUOTE` with intent.
>   - SDK: removes `getStarted` state/APIs.
> - Tests/Snapshots: add intent test; update navbar options; change
config button `testID` to `deposit-configuration-menu-button` and icon
to `Setting`; snapshot adjustments.
> - **Deposit**
> - Remove `GetStarted` view/styles/tests; `Root` now renders nothing
and immediately redirects based on token/order state.
>   - SDK: removes `getStarted` state/APIs.
>   - Tests: updated to reflect new redirects and SDK surface.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5385463. 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?
-->

The network request code within the client makes use of the circuit
breaker pattern. Currently, there must be 28 consecutive failed attempts
to hit an RPC endpoint before the circuit breaks and it is perceived to
be unavailable. At this point, if the endpoint is configured with a
failover, the failover will be activated and all requests will be
automatically diverted to it; otherwise requests are paused for 30
minutes.

There are two problems we are seeing now:

- If Infura is degraded enough to where failing over to QuickNode is
warranted, the failover may be activated too late.
- If the user is attempting to access a custom network and they are
experiencing issues (either due to a local connection issue or an issue
with the endpoint itself), they will be prevented from using that
network for 30 minutes. This is way too long.

To fix these problems, this commit:

- Lowers the "max consecutive failures" (the number of successive
attempts to obtain a successful response from an endpoint before
requests are paused or the failover is triggered) from 28 to 8.
- Lowers the "circuit break duration" (the period during which requests
to an unavailable endpoint will be paused) from 30 minutes to 30
*seconds*.

In summary, if a network starts to become degraded or the user is
experiencing connection issues, the network is more likely to be flagged
as unavailable, but if the situation improves the user may be able to
use the network more quickly.

How quickly does the circuit break now? It depends on whether the errors
encountered are retriable or non-retriable:

- Retriable errors (e.g. connection errors, 502/503/504, etc.) will, as
the name implies, be automatically retried. If these errors are
continually produced, the circuit will break very quickly (if the
extension is restarted, then it will break immediately).
- Non-retriable errors (e.g. 4xx errors) do not get automatically
retried, so it takes longer for the circuit to break.

**One final note is that on Mobile, requests do not take place as
frequently as on Extension, because the mechanism and cadence used to
poll for tokens and balances is a bit different. Therefore we may need
to use different values here than on Extension.**

## **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: Decrease time before activating QuickNode when Infura
is degraded or unavailable; decrease time before allowing users to
interact with a custom network following connection issues

## **Related issues**

- https://consensyssoftware.atlassian.net/browse/WPC-103

## **Manual testing steps**

(NOTE: These steps will only work on iOS, as the Simulator uses the
system network settings, so we can set a proxy that way. You can
probably set a proxy on the Android emulator via Android Studio, but
I've never gotten it to work. If you can, great!)

### Prerequisites

1. Check out this branch. Run `yarn setup:expo`, then `yarn
watch:clean`.
2. Ensure that you have a development build on your emulator/device.
3. Open MetaMask on your emulator/device, and go through onboarding.
4. Open DevTools by pressing `j`.
5. Install
[`mitmproxy`](https://docs.mitmproxy.org/stable/overview/installation/).
Make sure you [install the certificate on the
Simulator](https://docs.mitmproxy.org/stable/concepts/certificates/).
6. Create a Python script somewhere on your computer with the following
contents:
https://gist.github.com/mcmire/1d43ce690d3a974217126cd584f79b7d. This
script will cause all requests to Infura RPC endpoints to respond with
500, simulating an outage.
7. Run `mitmproxy -s <path to your script>` in an open terminal session.
This will run the proxy server.
8. Go to the network settings on your computer. Add both an HTTP and
HTTP proxy that points to `http://localhost:8080`. On macOS:
    1. Click on the Network icon in the menu bar.
    2. Go to Wifi Settings.
    3. Click on Details next to your active network
    4. Click on Proxies in the sidebar.
    5. Enable "Web proxy (HTTP)"
    6. Enter 127.0.0.1 for "Server" and 8080 for "Port".
    7. Do the same thing for "Secure web proxy (HTTPS)".

### Testing non-retriable errors

1. Ensure that in the `mitmproxy` script, all Infura endpoints return
500.
2. Restart the app.
3. Switch to DevTools. You should see an entry in the Console view like
`RPC endpoint not found or unavailable`.
4. On the home screen, pull down on the tokens list several times.
Eventually, you wil see a message `Creating Segment event "RPC Service
Unavailable"`. This indicates that the circuit broke.
5. If you pull down on the tokens list a few times in quick succession,
you will not see `Creating Segment event "RPC Service Unavailable"`.
But, if you wait 30 seconds and pull down again, then you will see it.

### Testing retriable errors

1. Stop `mitmproxy`. Modify the script so that all Infura endpoints
return 503 instead of 500. Restart it.
2. Restart the app.
3. Switch to DevTools. You should see already see an entry in the
Console view like `Creating Segment event "RPC Service Unavailable"`.

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

In this video, the endpoint continually responds with 500 (a
non-retriable error):


https://github.com/user-attachments/assets/ec89d2e0-585a-4d0c-98ec-242b154e8cee

In this video, the endpoint continually responds with 503 (a retriable
error):


https://github.com/user-attachments/assets/b6e5f237-07ef-45ba-959b-9e92258f1145

## **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]
> Lowers RPC circuit-break thresholds and cooldown, uses shared
DEFAULT_MAX_RETRIES, and adjusts QuickNode/general failure limits for
faster failover and recovery.
> 
> - **Engine/Network**:
> - **RPC policy tuning in
`app/core/Engine/controllers/network-controller-init.ts`**:
>     - Use `DEFAULT_MAX_RETRIES` for `maxRetries`.
> - Introduce shared `policyOptions` with `circuitBreakDuration: 30 *
SECOND`.
>     - Adjust `maxConsecutiveFailures`:
>       - QuickNode: `(maxRetries + 1) * 10`.
>       - Other endpoints: `(maxRetries + 1) * 3`.
>     - Keep common transport options (`fetch`, `btoa`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f34d509. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…n view (#22595)

## **Description**

This PR implements an informational modal that displays when users tap
the info icon next to unsupported tokens in the token selection list.
This helps users understand why certain tokens may not be available for
purchase in their region or through local payment providers.

**Changes include:**
- New `UnsupportedTokenModal` component that displays a clear message
about token availability
- Added info icon to disabled tokens in the token list
- Updated navigation flow to direct users to token selection screen for
buy flow
- Enhanced type safety with `MockDepositCryptoCurrency` type that
includes `unsupported` field
- Improved `useSearchTokenResults` hook with better memoization and
typing
- Added localized strings for unsupported token messaging

## **Changelog**

CHANGELOG entry: Added informational modal explaining why certain tokens
may be unavailable for purchase

## **Related issues**

Fixes: [TRAM-2793
](https://consensyssoftware.atlassian.net/browse/TRAM-2818)

## **Manual testing steps**

```gherkin
Feature: Unsupported Token Information

  Scenario: user views information about unsupported token
    Given user is on the token selection screen
    And there is at least one unsupported token in the list (e.g., USDT or BTC)
    
    When user taps on the info icon next to an unsupported token
    Then an informational modal appears
    And the modal displays the title "Not available"
    And the modal displays the description explaining regional/provider limitations
    And user can close the modal by tapping the close button

  Scenario: user navigates to buy flow
    Given user is on the main wallet screen
    
    When user initiates a buy action
    Then user is directed to the token selection screen
    And user can see all available tokens with their network information
```

## **Screenshots/Recordings**

### **Before**

<!-- No unsupported token modal existed -->

### **After**

<!-- Please add screenshots showing:
1. Token list with info icon on unsupported tokens (USDT, BTC)
2. Modal opened showing the unsupported token message
-->

<img width="201" height="437" alt="Simulator Screenshot - iPhone 16 Pro
- 2025-11-13 at 14 57 44"
src="https://github.com/user-attachments/assets/ed3a0769-2e21-481d-b554-bd7a9f8879d8"
/>

<img width="201" height="437" alt="Simulator Screenshot - iPhone 16 Pro
- 2025-11-13 at 14 57 59"
src="https://github.com/user-attachments/assets/bbf7a48e-870c-4b1d-9d2c-137b32d230e3"
/>


## **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]
> Adds an unsupported token info modal and integrates a new token list
navigation stack, with disabled-token UX and improved token search.
> 
> - **UI/Ramp**:
> - Adds `UnsupportedTokenModal` (new component, styles, tests) and
navigates to it from disabled tokens.
> - `TokenSelection`: disables unsupported tokens, shows info button,
and opens modal; updates list rendering to use
`MockDepositCryptoCurrency`.
>   - `TokenListItem`: adds optional info icon when item is disabled.
> - Improves token search (`useSearchTokenResults`): stronger typing,
memoized results, adjusted Fuse threshold.
> - **Navigation/Routes**:
> - Replaces `RampTokenSelection` screen with `TokenListRoutes` stack
(main + `RampModals`), wires modal route
`Routes.RAMP.MODALS.UNSUPPORTED_TOKEN`.
>   - Updates `MainNavigator` to use `TokenListRoutes`.
> - **Mocks/Constants**:
>   - Extends mock deposit tokens with `unsupported` flag.
> - **Tests/Snapshots**:
> - Adds/updates tests for token selection, unsupported modal, and order
list snapshots reflecting `unsupported` tokens and disabled states.
> - **i18n**:
>   - Adds strings for unsupported token modal title/description.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
aa422cd. 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 Nov 17, 2025
@pull pull Bot added the ⤵️ pull label Nov 17, 2025
@pull pull Bot merged commit 7bac5f2 into Reality2byte:main Nov 17, 2025
7 of 39 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.

5 participants