Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/ramps-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ 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 ([#9448](https://github.com/MetaMask/core/pull/9448))
- Bump `@metamask/profile-sync-controller` from `^28.2.0` to `^28.3.0` ([#9463](https://github.com/MetaMask/core/pull/9463))

### Removed

- **BREAKING:** Remove the `normalizeProviderCode` export ([#9448](https://github.com/MetaMask/core/pull/9448))

## [15.1.0]

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
68 changes: 52 additions & 16 deletions packages/ramps-controller/src/RampsController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type {
UserRegion,
} from './RampsController';
import {
normalizeProviderCode,
RampsController,
getDefaultRampsControllerState,
RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS,
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -761,6 +746,57 @@ 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)],
Expand Down Expand Up @@ -8023,7 +8059,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);
});
Expand Down
29 changes: 9 additions & 20 deletions packages/ramps-controller/src/RampsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand All @@ -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 => {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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.
*/
Expand All @@ -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: '',
Expand Down
1 change: 0 additions & 1 deletion packages/ramps-controller/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export {
RampsController,
getDefaultRampsControllerState,
getInternalOrderCode,
normalizeProviderCode,
RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS,
} from './RampsController';
export type {
Expand Down