From 5826c071029d98e5a6e36abaf2d78c0cf5c3beac Mon Sep 17 00:00:00 2001 From: Darius Costolas <10818970+meltingice1337@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:43:23 +0300 Subject: [PATCH 1/5] feat: remove provider ID normalization and update related functionality --- packages/ramps-controller/CHANGELOG.md | 8 +++++ .../src/RampsController.test.ts | 17 +---------- .../ramps-controller/src/RampsController.ts | 29 ++++++------------- packages/ramps-controller/src/index.ts | 1 - 4 files changed, 18 insertions(+), 37 deletions(-) diff --git a/packages/ramps-controller/CHANGELOG.md b/packages/ramps-controller/CHANGELOG.md index 362d9d0c14..f296de4241 100644 --- a/packages/ramps-controller/CHANGELOG.md +++ b/packages/ramps-controller/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Provider IDs are no longer normalized by stripping a `/providers/` prefix. `RampsController.getQuotes` now matches provider IDs from the providers list, quotes, custom actions, and sort order as-is, and a precreated stub order's `provider.id` is the canonical provider code passed to the create-order call rather than a `/providers/`-prefixed value. Consumers must supply non-prefixed (canonical) provider IDs ([#0000](https://github.com/MetaMask/core/pull/0000)) + +### Removed + +- **BREAKING:** Remove the `normalizeProviderCode` export ([#0000](https://github.com/MetaMask/core/pull/0000)) + ## [15.1.0] ### Added diff --git a/packages/ramps-controller/src/RampsController.test.ts b/packages/ramps-controller/src/RampsController.test.ts index f4543d9f64..529b6cd045 100644 --- a/packages/ramps-controller/src/RampsController.test.ts +++ b/packages/ramps-controller/src/RampsController.test.ts @@ -16,7 +16,6 @@ import type { UserRegion, } from './RampsController'; import { - normalizeProviderCode, RampsController, getDefaultRampsControllerState, RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS, @@ -66,20 +65,6 @@ describe('RampsController', () => { const circuitBreakerOpenErrorMessage = 'Execution prevented because the circuit breaker is open'; - describe('normalizeProviderCode', () => { - it('strips /providers/ prefix', () => { - expect(normalizeProviderCode('/providers/transak')).toBe('transak'); - expect(normalizeProviderCode('/providers/transak-staging')).toBe( - 'transak-staging', - ); - }); - - it('returns string unchanged when no prefix', () => { - expect(normalizeProviderCode('transak')).toBe('transak'); - expect(normalizeProviderCode('')).toBe(''); - }); - }); - describe('RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS', () => { it('includes every RampsService action that RampsController calls', async () => { expect.hasAssertions(); @@ -8023,7 +8008,7 @@ describe('RampsController', () => { expect(controller.state.orders).toHaveLength(1); const stub = controller.state.orders[0]; expect(stub?.providerOrderId).toBe('abc123'); - expect(stub?.provider?.id).toBe('/providers/paypal'); + expect(stub?.provider?.id).toBe('paypal'); expect(stub?.walletAddress).toBe('0xabc'); expect(stub?.status).toBe(RampsOrderStatus.Precreated); }); diff --git a/packages/ramps-controller/src/RampsController.ts b/packages/ramps-controller/src/RampsController.ts index 6187c4a497..40d50481bd 100644 --- a/packages/ramps-controller/src/RampsController.ts +++ b/packages/ramps-controller/src/RampsController.ts @@ -765,10 +765,6 @@ function findRegionFromCode( }; } -export function normalizeProviderCode(providerCode: string): string { - return providerCode.replace(/^\/providers\//u, ''); -} - /** * Returns the internal MetaMask order code used for state lookups and polling. * Prefers the code embedded in the canonical order `id` path over `providerOrderId`, @@ -2089,21 +2085,16 @@ export class RampsController extends BaseController< }, ): Quote | undefined { const providerByCode = new Map( - providers.map((provider) => [ - normalizeProviderCode(provider.id), - provider, - ]), + providers.map((provider) => [provider.id, provider]), ); const customActionProviderCodes = new Set( - response.customActions.map((action: QuoteCustomAction) => - normalizeProviderCode(action.buy.providerId), + response.customActions.map( + (action: QuoteCustomAction) => action.buy.providerId, ), ); const fitsProviderLimits = (quote: Quote): boolean => { - const provider = providerByCode.get( - normalizeProviderCode(quote.provider), - ); + const provider = providerByCode.get(quote.provider); const limit = provider?.limits?.fiat?.[fiat]?.[quote.quote.paymentMethod]; if (!limit) { // No published limits for this provider/payment method: treat as @@ -2117,7 +2108,7 @@ export class RampsController extends BaseController< // `all` (Phase 2) skips the in-app-only exclusions; both scopes still // enforce provider limits up front. if (scope !== 'all') { - const providerCode = normalizeProviderCode(quote.provider); + const providerCode = quote.provider; if (customActionProviderCodes.has(providerCode)) { return false; } @@ -2141,7 +2132,7 @@ export class RampsController extends BaseController< } const candidateByCode = new Map( - candidates.map((quote) => [normalizeProviderCode(quote.provider), quote]), + candidates.map((quote) => [quote.provider, quote]), ); const pickBySortOrder = (sortBy: QuoteSortBy): Quote | undefined => { @@ -2152,7 +2143,7 @@ export class RampsController extends BaseController< return undefined; } for (const providerId of order) { - const match = candidateByCode.get(normalizeProviderCode(providerId)); + const match = candidateByCode.get(providerId); if (match) { return match; } @@ -2581,7 +2572,7 @@ export class RampsController extends BaseController< * * @param params - Object containing order identifiers and wallet info. * @param params.orderId - Full order ID (e.g. "/providers/paypal/orders/abc123") or order code. - * @param params.providerCode - Provider code (e.g. "paypal", "transak"), with or without /providers/ prefix. + * @param params.providerCode - Canonical provider code (e.g. "paypal", "transak"). * @param params.walletAddress - Wallet address for the order. * @param params.chainId - Optional chain ID for the order. */ @@ -2597,12 +2588,10 @@ export class RampsController extends BaseController< if (!orderCode?.trim()) { return; } - const normalizedProviderCode = normalizeProviderCode(providerCode); - const stubOrder: RampsOrder = { providerOrderId: orderCode, provider: { - id: `/providers/${normalizedProviderCode}`, + id: providerCode, name: '', environmentType: '', description: '', diff --git a/packages/ramps-controller/src/index.ts b/packages/ramps-controller/src/index.ts index 372bcdefa9..5c651567a9 100644 --- a/packages/ramps-controller/src/index.ts +++ b/packages/ramps-controller/src/index.ts @@ -66,7 +66,6 @@ export { RampsController, getDefaultRampsControllerState, getInternalOrderCode, - normalizeProviderCode, RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS, } from './RampsController'; export type { From b447290d5469b2561d8abb6b8e1ba1b1d7d8fed9 Mon Sep 17 00:00:00 2001 From: Darius Costolas <10818970+meltingice1337@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:48:21 +0300 Subject: [PATCH 2/5] feat: update changelog for breaking changes in provider ID normalization and removal of normalizeProviderCode export --- packages/ramps-controller/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ramps-controller/CHANGELOG.md b/packages/ramps-controller/CHANGELOG.md index f296de4241..971ba01151 100644 --- a/packages/ramps-controller/CHANGELOG.md +++ b/packages/ramps-controller/CHANGELOG.md @@ -9,11 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- **BREAKING:** Provider IDs are no longer normalized by stripping a `/providers/` prefix. `RampsController.getQuotes` now matches provider IDs from the providers list, quotes, custom actions, and sort order as-is, and a precreated stub order's `provider.id` is the canonical provider code passed to the create-order call rather than a `/providers/`-prefixed value. Consumers must supply non-prefixed (canonical) provider IDs ([#0000](https://github.com/MetaMask/core/pull/0000)) +- **BREAKING:** Provider IDs are no longer normalized by stripping a `/providers/` prefix. `RampsController.getQuotes` now matches provider IDs from the providers list, quotes, custom actions, and sort order as-is, and a precreated stub order's `provider.id` is the canonical provider code passed to the create-order call rather than a `/providers/`-prefixed value. Consumers must supply non-prefixed (canonical) provider IDs ([#9448](https://github.com/MetaMask/core/pull/9448)) ### Removed -- **BREAKING:** Remove the `normalizeProviderCode` export ([#0000](https://github.com/MetaMask/core/pull/0000)) +- **BREAKING:** Remove the `normalizeProviderCode` export ([#9448](https://github.com/MetaMask/core/pull/9448)) ## [15.1.0] From d67a44dc1cf8cd6b703016a8702d37a6b09e2b8f Mon Sep 17 00:00:00 2001 From: Darius Costolas <10818970+meltingice1337@users.noreply.github.com> Date: Thu, 9 Jul 2026 18:05:17 +0300 Subject: [PATCH 3/5] chore: regenerate ramps-controller messenger action types The messenger-action-types:check CI step failed because RampsController-method-action-types.ts embeds the getBuyWidgetData method JSDoc, which changed when the providerCode param doc was updated to describe canonical (non-prefixed) provider codes. Regenerated via messenger-action-types --generate. --- .../ramps-controller/src/RampsController-method-action-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ramps-controller/src/RampsController-method-action-types.ts b/packages/ramps-controller/src/RampsController-method-action-types.ts index ecf4b046d9..4792d073e0 100644 --- a/packages/ramps-controller/src/RampsController-method-action-types.ts +++ b/packages/ramps-controller/src/RampsController-method-action-types.ts @@ -289,7 +289,7 @@ export type RampsControllerGetBuyWidgetDataAction = { * * @param params - Object containing order identifiers and wallet info. * @param params.orderId - Full order ID (e.g. "/providers/paypal/orders/abc123") or order code. - * @param params.providerCode - Provider code (e.g. "paypal", "transak"), with or without /providers/ prefix. + * @param params.providerCode - Canonical provider code (e.g. "paypal", "transak"). * @param params.walletAddress - Wallet address for the order. * @param params.chainId - Optional chain ID for the order. */ From f763af0c75e137ebab9ccd41e85eeedf4ae790a6 Mon Sep 17 00:00:00 2001 From: Darius Costolas <10818970+meltingice1337@users.noreply.github.com> Date: Fri, 10 Jul 2026 11:41:51 +0300 Subject: [PATCH 4/5] feat: add test for quote selection with unprefixed provider IDs --- .../src/RampsController.test.ts | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/packages/ramps-controller/src/RampsController.test.ts b/packages/ramps-controller/src/RampsController.test.ts index 529b6cd045..c97aa23f34 100644 --- a/packages/ramps-controller/src/RampsController.test.ts +++ b/packages/ramps-controller/src/RampsController.test.ts @@ -746,6 +746,55 @@ describe('RampsController', () => { ); }); + it('selects the correct quote when provider IDs carry no /providers/ prefix', async () => { + // The PR removed provider-code normalization: the provider list, quotes, + // custom actions, and sort-order arrive with plain, unprefixed IDs and + // must match each other directly. + const PLAIN_MOONPAY = 'moonpay'; + const PLAIN_REVOLUT = 'revolut'; + + const response: QuotesResponse = { + success: [ + inAppScopeQuote(PLAIN_MOONPAY, 90), + inAppScopeQuote(PLAIN_REVOLUT, 80), + ], + sorted: [{ sortBy: 'reliability', ids: [PLAIN_MOONPAY, PLAIN_REVOLUT] }], + error: [], + customActions: [ + { + buy: { providerId: PLAIN_MOONPAY }, + paymentMethodId: SCOPE_PAYMENT_METHOD, + supportedPaymentMethodIds: [SCOPE_PAYMENT_METHOD], + }, + ], + }; + + await withController( + { + options: { + getProviderScope: () => 'in-app', + state: scopeState([ + buildScopeProvider(PLAIN_MOONPAY, 'aggregator'), + buildScopeProvider(PLAIN_REVOLUT, 'aggregator'), + ]), + }, + }, + async ({ messenger, rootMessenger }) => { + rootMessenger.registerActionHandler( + 'RampsService:getQuotes', + async () => response, + ); + + const quotes = await callScopedGetQuotes(messenger); + + // MoonPay is a custom action, so Revolut wins despite ranking higher, + // proving the plain IDs matched across the provider list, quote, + // custom action, and sort-order without normalization. + expect(quotes.success[0]?.provider).toBe(PLAIN_REVOLUT); + }, + ); + }); + it('does not widen and does not mutate providers.selected when the scope is off', async () => { const response: QuotesResponse = { success: [inAppScopeQuote(NATIVE, 70)], From 74ff3b12dc337a962c72b79c84888a0fcdb5a06f Mon Sep 17 00:00:00 2001 From: Darius Costolas <10818970+meltingice1337@users.noreply.github.com> Date: Fri, 10 Jul 2026 11:48:36 +0300 Subject: [PATCH 5/5] fix: format sorted array in RampsController test for better readability --- packages/ramps-controller/src/RampsController.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ramps-controller/src/RampsController.test.ts b/packages/ramps-controller/src/RampsController.test.ts index c97aa23f34..4e7f643d42 100644 --- a/packages/ramps-controller/src/RampsController.test.ts +++ b/packages/ramps-controller/src/RampsController.test.ts @@ -758,7 +758,9 @@ describe('RampsController', () => { inAppScopeQuote(PLAIN_MOONPAY, 90), inAppScopeQuote(PLAIN_REVOLUT, 80), ], - sorted: [{ sortBy: 'reliability', ids: [PLAIN_MOONPAY, PLAIN_REVOLUT] }], + sorted: [ + { sortBy: 'reliability', ids: [PLAIN_MOONPAY, PLAIN_REVOLUT] }, + ], error: [], customActions: [ {