diff --git a/packages/ramps-controller/CHANGELOG.md b/packages/ramps-controller/CHANGELOG.md index 65c60b9343a..3a069e0a568 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 + +- `setSelectedProvider` no longer fetches payment methods when the selected token is explicitly not supported by the new provider, preventing empty payment method state with no user feedback ([#8103](https://github.com/MetaMask/core/pull/8103)) + ## [10.1.0] ### Added diff --git a/packages/ramps-controller/src/RampsController.test.ts b/packages/ramps-controller/src/RampsController.test.ts index e9391e4070c..9d745fe7011 100644 --- a/packages/ramps-controller/src/RampsController.test.ts +++ b/packages/ramps-controller/src/RampsController.test.ts @@ -2600,6 +2600,126 @@ describe('RampsController', () => { }, ); }); + + it('skips getPaymentMethods when selected token is explicitly not supported by the new provider', async () => { + const unsupportedToken: RampsToken = { + assetId: 'eip155:1/slip44:0', + chainId: 'eip155:1', + name: 'Bitcoin', + symbol: 'BTC', + decimals: 8, + iconUrl: '', + tokenSupported: true, + }; + + const providerWithExclusion: Provider = { + ...mockProvider, + supportedCryptoCurrencies: { + 'eip155:1/slip44:60': true, + [unsupportedToken.assetId]: false, + }, + }; + + const getPaymentMethodsMock = jest.fn(async () => ({ payments: [] })); + + await withController( + { + options: { + state: { + userRegion: createMockUserRegion('us-ca'), + providers: createResourceState([providerWithExclusion], null), + tokens: createResourceState(null, unsupportedToken), + }, + }, + }, + async ({ controller, rootMessenger }) => { + rootMessenger.registerActionHandler( + 'RampsService:getPaymentMethods', + getPaymentMethodsMock, + ); + + controller.setSelectedProvider(providerWithExclusion.id); + + expect(getPaymentMethodsMock).not.toHaveBeenCalled(); + }, + ); + }); + + it('fetches getPaymentMethods when provider has no supportedCryptoCurrencies field', async () => { + const providerWithoutField: Provider = { ...mockProvider }; + delete (providerWithoutField as Partial) + .supportedCryptoCurrencies; + + const getPaymentMethodsMock = jest.fn(async () => ({ payments: [] })); + + await withController( + { + options: { + state: { + userRegion: createMockUserRegion('us-ca'), + providers: createResourceState([providerWithoutField], null), + }, + }, + }, + async ({ controller, rootMessenger }) => { + rootMessenger.registerActionHandler( + 'RampsService:getPaymentMethods', + getPaymentMethodsMock, + ); + + controller.setSelectedProvider(providerWithoutField.id); + + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(getPaymentMethodsMock).toHaveBeenCalledTimes(1); + }, + ); + }); + + it('fetches getPaymentMethods when selected token is explicitly supported by the new provider', async () => { + const supportedToken: RampsToken = { + assetId: 'eip155:1/slip44:60', + chainId: 'eip155:1', + name: 'Ether', + symbol: 'ETH', + decimals: 18, + iconUrl: '', + tokenSupported: true, + }; + + const providerWithSupport: Provider = { + ...mockProvider, + supportedCryptoCurrencies: { + [supportedToken.assetId]: true, + }, + }; + + const getPaymentMethodsMock = jest.fn(async () => ({ payments: [] })); + + await withController( + { + options: { + state: { + userRegion: createMockUserRegion('us-ca'), + providers: createResourceState([providerWithSupport], null), + tokens: createResourceState(null, supportedToken), + }, + }, + }, + async ({ controller, rootMessenger }) => { + rootMessenger.registerActionHandler( + 'RampsService:getPaymentMethods', + getPaymentMethodsMock, + ); + + controller.setSelectedProvider(providerWithSupport.id); + + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(getPaymentMethodsMock).toHaveBeenCalledTimes(1); + }, + ); + }); }); describe('setSelectedToken', () => { diff --git a/packages/ramps-controller/src/RampsController.ts b/packages/ramps-controller/src/RampsController.ts index 23a4b10fad6..8b39f6b1323 100644 --- a/packages/ramps-controller/src/RampsController.ts +++ b/packages/ramps-controller/src/RampsController.ts @@ -1183,14 +1183,28 @@ export class RampsController extends BaseController< ); } + const selectedToken = this.state.tokens.selected; + const supportedCryptos = provider.supportedCryptoCurrencies; + + // Only fetch payment methods if the selected token is supported by the new + // provider. If it isn't, the payment methods request would fail or return + // empty for the wrong reason; the UI will show the Token Not Available modal + // so the user can change token or pick a different provider. + const tokenSupportedByProvider = + !selectedToken || + !supportedCryptos || + supportedCryptos[selectedToken.assetId] !== false; + this.update((state) => { state.providers.selected = provider; resetResource(state, 'paymentMethods'); }); - this.#fireAndForget( - this.getPaymentMethods(regionCode, { provider: provider.id }), - ); + if (tokenSupportedByProvider) { + this.#fireAndForget( + this.getPaymentMethods(regionCode, { provider: provider.id }), + ); + } } /**