Commit 44c33a8
authored
feat(ramp): implement dynamic token fetching for token selection screen (#22892)
## **Description**
This PR implements **TRAM-2820**: Dynamic token fetching for the Token
Selection screen in the Ramp flow, replacing hardcoded mock data with
real-time API data from the on-ramp-cache endpoint.
### **What changed and why:**
**Problem:** The Token Selection screen was using hardcoded
`MOCK_CRYPTOCURRENCIES` data, preventing users from seeing the actual
available tokens for their region and selected flow (Buy vs Deposit).
**Solution:**
1. **Created `useRampTokens` hook** to fetch tokens from the
on-ramp-cache API endpoint
2. **Integrated hook into TokenSelection component** with loading and
error states
3. **Added network filtering** to only show tokens for networks the user
has added to their wallet
4. **Implemented smart list switching** - displays curated `topTokens`
by default, switches to complete `allTokens` when searching
### **Key Features:**
- ✅ **Environment-aware API calls**: Uses staging or production URLs
based on `METAMASK_ENVIRONMENT`
- ✅ **Region-based tokens**: Fetches tokens based on user's detected
geolocation
- ✅ **Flow-aware**: Different token lists for Aggregator (buy) vs
Deposit flows
- ✅ **Network filtering**: Only shows tokens for networks in user's
wallet (e.g., excludes Tron if user doesn't have Tron network)
- ✅ **Smart UX**: Shows curated top tokens initially, searches across
all tokens
- ✅ **Loading/Error states**: Proper UI feedback during fetch and on
errors
- ✅ **Type-safe**: Full TypeScript support with `RampsToken` interface
### **Technical Details:**
**API Endpoint:**
```
{baseUrl}/regions/{region}/tokens?action={action}&sdk=2.1.5
```
**Mapping:**
- `UnifiedRampRoutingType.AGGREGATOR` → `action=buy`
- `UnifiedRampRoutingType.DEPOSIT` → `action=deposit`
**Response Structure:**
```json
{
"topTokens": [...], // Curated list
"allTokens": [...] // Complete list
}
```
**Previous work included in this PR (refactoring):**
- Standardized navigation using `getDepositNavbarOptions()`
- Migrated to `ScreenLayout` component
- Converted styles to Tailwind CSS with `twClassName`
- Updated parameter structure from `selectedCryptoAssetId` to
`intent.assetId`
---
## **Changelog**
CHANGELOG entry: null
---
## **Related issues**
Refs:
[TRAM-2820](https://consensyssoftware.atlassian.net/browse/TRAM-2820)
---
## **Manual testing steps**
```gherkin
Feature: Dynamic Token Fetching
Scenario: user views token selection screen with real tokens
Given user is in a supported region (e.g., US-CA)
And user has Ethereum network in wallet
When user navigates to token selection screen
Then user sees loading indicator
And user sees tokens fetched from API
And user sees supported tokens displayed normally
And user sees unsupported tokens greyed out with info icon
Scenario: user searches across all available tokens
Given user is on token selection screen
And curated top tokens are displayed
When user types in search field
Then search switches to complete token list
And user sees all matching tokens (supported and unsupported)
When user clears search
Then screen returns to showing curated top tokens
Scenario: user only sees tokens for networks they have
Given user has only Ethereum network in wallet
And API returns tokens for Ethereum, Tron, and Solana
When screen loads
Then user sees only Ethereum tokens
And Tron and Solana tokens are filtered out
Scenario: error handling when API fails
Given API is unavailable or returns error
When user navigates to token selection screen
Then user sees error message
And user can close the screen
Scenario: no region detected
Given user's region cannot be detected
When user navigates to token selection screen
Then no API call is made
And appropriate state is shown
```
---
## **Screenshots/Recordings**
### **Before**
- Used hardcoded `MOCK_CRYPTOCURRENCIES` (5 tokens only)
- No loading states
- No error handling
- Custom navigation setup
- StyleSheet-based styling
### **After**
- Dynamic token fetching from API (25+ tokens)
- Loading indicator while fetching
- Error message on fetch failure
- Standard Ramp navigation pattern
- Tailwind CSS styling
- Network-based filtering
- Smart list switching (topTokens/allTokens)
https://github.com/user-attachments/assets/fc623885-1fc7-4f5e-8b19-921511e4e255
---
## **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.
---
## **Files Changed Summary**
### **New Files:**
1. `app/components/UI/Ramp/hooks/useRampTokens.ts` - Hook to fetch
tokens from API
2. `app/components/UI/Ramp/hooks/useRampTokens.test.ts` - Comprehensive
tests (24 test cases)
3.
`app/components/UI/Ramp/components/TokenListItem/TokenListItem.test.tsx`
- Component tests (12 test cases)
### **Modified Files:**
4. `app/components/UI/Ramp/components/TokenSelection/TokenSelection.tsx`
- Integrated hook, added loading/error states
5.
`app/components/UI/Ramp/components/TokenSelection/TokenSelection.test.tsx`
- Updated tests for hook integration
6. `app/components/UI/Ramp/components/TokenListItem/TokenListItem.tsx` -
Made `isSelected` optional, removed from usage
7. `babel.config.tests.js` - Added hook files to process.env exclude
list
8. `locales/languages/en.json` - Added error message localization
### **Deleted Files:**
9.
`app/components/UI/Ramp/components/TokenSelection/TokenSelection.styles.ts`
- Migrated to Tailwind
[TRAM-2820]:
https://consensyssoftware.atlassian.net/browse/TRAM-2820?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Introduce useRampTokens to fetch region- and flow-aware tokens from
on-ramp cache and integrate into TokenSelection with loading/error
states, network filtering, and UI tweaks.
>
> - **Ramp tokens fetching**:
> - Add `useRampTokens` hook to fetch tokens from env-aware on-ramp
cache (`production`/`staging`) with `action=buy|deposit` and `sdk`
version.
> - Filter tokens by user-added networks; expose `topTokens`,
`allTokens`, `isLoading`, `error`.
> - **TokenSelection**:
> - Replace mock data with `useRampTokens` output; default to
`topTokens`, switch to `allTokens` when searching.
> - Add loading spinner and localized error state
(`deposit.token_modal.error_loading_tokens`).
> - Apply network filter bar using unique chains from fetched tokens.
> - Remove intent-based selection; mark unsupported via
`!token.tokenSupported` and show info modal.
> - **TokenListItem**:
> - Make `isSelected` optional; show `token.name` primary and
`token.symbol` secondary; use `depositNetworkName ?? networkName` for
badge; enable info button for disabled items.
> - **Tests & config**:
> - Add comprehensive tests for `useRampTokens`, `TokenSelection`, and
`TokenListItem` (snapshots and behaviors).
> - Update `babel.config.tests.js` to avoid inlining env vars for new
hook files.
> - Update snapshots reflecting name/symbol swap and disabled/state
changes.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5dadc12. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent b60cba2 commit 44c33a8
File tree
11 files changed
+1913
-2218
lines changed- app/components/UI/Ramp
- Deposit/Views/Modals/TokenSelectorModal/__snapshots__
- components
- TokenListItem
- __snapshots__
- TokenSelection
- __snapshots__
- hooks
- locales/languages
11 files changed
+1913
-2218
lines changedLines changed: 10 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3019 | 3019 | | |
3020 | 3020 | | |
3021 | 3021 | | |
3022 | | - | |
3023 | | - | |
3024 | 3022 | | |
3025 | 3023 | | |
3026 | 3024 | | |
| |||
3207 | 3205 | | |
3208 | 3206 | | |
3209 | 3207 | | |
3210 | | - | |
| 3208 | + | |
3211 | 3209 | | |
3212 | 3210 | | |
3213 | 3211 | | |
| |||
3221 | 3219 | | |
3222 | 3220 | | |
3223 | 3221 | | |
3224 | | - | |
| 3222 | + | |
3225 | 3223 | | |
3226 | 3224 | | |
3227 | 3225 | | |
| |||
3261 | 3259 | | |
3262 | 3260 | | |
3263 | 3261 | | |
3264 | | - | |
3265 | | - | |
3266 | 3262 | | |
3267 | 3263 | | |
3268 | 3264 | | |
| |||
3449 | 3445 | | |
3450 | 3446 | | |
3451 | 3447 | | |
3452 | | - | |
| 3448 | + | |
3453 | 3449 | | |
3454 | 3450 | | |
3455 | 3451 | | |
| |||
3463 | 3459 | | |
3464 | 3460 | | |
3465 | 3461 | | |
3466 | | - | |
| 3462 | + | |
3467 | 3463 | | |
3468 | 3464 | | |
3469 | 3465 | | |
| |||
3476 | 3472 | | |
3477 | 3473 | | |
3478 | 3474 | | |
3479 | | - | |
3480 | | - | |
3481 | 3475 | | |
3482 | 3476 | | |
3483 | 3477 | | |
| |||
3664 | 3658 | | |
3665 | 3659 | | |
3666 | 3660 | | |
3667 | | - | |
| 3661 | + | |
3668 | 3662 | | |
3669 | 3663 | | |
3670 | 3664 | | |
| |||
3678 | 3672 | | |
3679 | 3673 | | |
3680 | 3674 | | |
3681 | | - | |
| 3675 | + | |
3682 | 3676 | | |
3683 | 3677 | | |
3684 | 3678 | | |
| |||
3691 | 3685 | | |
3692 | 3686 | | |
3693 | 3687 | | |
3694 | | - | |
3695 | | - | |
3696 | 3688 | | |
3697 | 3689 | | |
3698 | 3690 | | |
| |||
3879 | 3871 | | |
3880 | 3872 | | |
3881 | 3873 | | |
3882 | | - | |
| 3874 | + | |
3883 | 3875 | | |
3884 | 3876 | | |
3885 | 3877 | | |
| |||
3893 | 3885 | | |
3894 | 3886 | | |
3895 | 3887 | | |
3896 | | - | |
| 3888 | + | |
3897 | 3889 | | |
3898 | 3890 | | |
3899 | 3891 | | |
| |||
3906 | 3898 | | |
3907 | 3899 | | |
3908 | 3900 | | |
3909 | | - | |
3910 | | - | |
3911 | 3901 | | |
3912 | 3902 | | |
3913 | 3903 | | |
| |||
4094 | 4084 | | |
4095 | 4085 | | |
4096 | 4086 | | |
4097 | | - | |
| 4087 | + | |
4098 | 4088 | | |
4099 | 4089 | | |
4100 | 4090 | | |
| |||
4108 | 4098 | | |
4109 | 4099 | | |
4110 | 4100 | | |
4111 | | - | |
| 4101 | + | |
4112 | 4102 | | |
4113 | 4103 | | |
4114 | 4104 | | |
| |||
Lines changed: 185 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
Lines changed: 7 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
56 | | - | |
57 | | - | |
58 | 56 | | |
59 | 57 | | |
60 | 58 | | |
61 | 59 | | |
62 | 60 | | |
63 | | - | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
| |||
71 | 72 | | |
72 | 73 | | |
73 | 74 | | |
74 | | - | |
| 75 | + | |
75 | 76 | | |
76 | | - | |
| 77 | + | |
77 | 78 | | |
78 | 79 | | |
79 | 80 | | |
| |||
0 commit comments