From 4556fdf8323a31256b185061cf31f79e1feba05a Mon Sep 17 00:00:00 2001 From: Amitabh Aggarwal Date: Tue, 3 Mar 2026 18:16:22 -0600 Subject: [PATCH] fix(ramps-controller): payment methods not loading after provider change when token unsupported - setSelectedProvider: use assetId the new provider supports (selected token or first supported) so payment-methods API succeeds - getPaymentMethods: apply response when provider matches; set selected payment method to first when fallback assetId was used Fixes TRAM-3314. Related TRAM-3315. Made-with: Cursor --- packages/ramps-controller/CHANGELOG.md | 4 +++ .../ramps-controller/src/RampsController.ts | 36 +++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/ramps-controller/CHANGELOG.md b/packages/ramps-controller/CHANGELOG.md index 6b8a78ef484..8d0bef922cc 100644 --- a/packages/ramps-controller/CHANGELOG.md +++ b/packages/ramps-controller/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Fix payment methods not loading after changing provider when the selected token is not supported by the new provider. The controller now requests payment methods using a supported asset (selected token when supported, otherwise the first supported asset from the provider) so the API succeeds and payment methods display. When the response was fetched with a fallback asset, the controller still applies the returned payment methods so the UI is not stuck in a loading or error state ([TRAM-3314](https://consensyssoftware.atlassian.net/browse/TRAM-3314), [TRAM-3315](https://consensyssoftware.atlassian.net/browse/TRAM-3315)). + ### Added - Added `orders: RampsOrder[]` to controller state with persistence, along with crud methods([#8045](https://github.com/MetaMask/core/pull/8045)) diff --git a/packages/ramps-controller/src/RampsController.ts b/packages/ramps-controller/src/RampsController.ts index 23a4b10fad6..93f2476fddb 100644 --- a/packages/ramps-controller/src/RampsController.ts +++ b/packages/ramps-controller/src/RampsController.ts @@ -1188,8 +1188,28 @@ export class RampsController extends BaseController< resetResource(state, 'paymentMethods'); }); + // Use an assetId the new provider supports so the payment-methods API succeeds. + // If the selected token is not supported by the new provider (e.g. after "change provider" + // from TokenNotAvailableModal), the API would fail or return empty, leaving payment methods + // not loading. Use selected token when supported, otherwise a fallback supported asset. + const selectedToken = this.state.tokens.selected; + const supportedAssetIds = Object.entries( + provider.supportedCryptoCurrencies ?? {}, + ) + .filter(([, supported]) => supported) + .map(([assetId]) => assetId); + const assetIdForPaymentMethods = + selectedToken && supportedAssetIds.includes(selectedToken.assetId) + ? selectedToken.assetId + : supportedAssetIds[0] ?? selectedToken?.assetId ?? ''; + this.#fireAndForget( - this.getPaymentMethods(regionCode, { provider: provider.id }), + this.getPaymentMethods(regionCode, { + provider: provider.id, + ...(assetIdForPaymentMethods + ? { assetId: assetIdForPaymentMethods } + : {}), + }), ); } @@ -1487,17 +1507,19 @@ export class RampsController extends BaseController< const tokenSelectionUnchanged = assetIdToUse === currentAssetId; const providerSelectionUnchanged = providerToUse === currentProviderId; - // this is a race condition check to ensure that the selected token and provider in state are the same as the tokens we're requesting for - // ex: if the user rapidly changes the token or provider, the in-flight payment methods might not be valid - // so this check will ensure that the payment methods are still valid for the token and provider that were requested - if (tokenSelectionUnchanged && providerSelectionUnchanged) { + // Race condition check: only apply when the provider we requested for is still selected. + // When setSelectedProvider used a fallback assetId (selected token not supported by new provider), + // tokenSelectionUnchanged is false but we still want to apply payment methods so the UI can show them. + if (providerSelectionUnchanged) { state.paymentMethods.data = response.payments; - // this will auto-select the first payment method if the selected payment method is not in the new payment methods const currentSelectionStillValid = response.payments.some( (pm: PaymentMethod) => pm.id === state.paymentMethods.selected?.id, ); - if (!currentSelectionStillValid) { + if ( + !currentSelectionStillValid || + !tokenSelectionUnchanged // used fallback assetId; reset selection to first + ) { state.paymentMethods.selected = response.payments[0] ?? null; } }