@metamask-previews/ramps-controller 15.1.0-preview-bbd2df29f → 15.1.0-preview-34f2bcbf7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +0 -16
  2. package/dist/RampsController.cjs +80 -39
  3. package/dist/RampsController.cjs.map +1 -1
  4. package/dist/RampsController.d.cts +5 -11
  5. package/dist/RampsController.d.cts.map +1 -1
  6. package/dist/RampsController.d.mts +5 -11
  7. package/dist/RampsController.d.mts.map +1 -1
  8. package/dist/RampsController.mjs +80 -39
  9. package/dist/RampsController.mjs.map +1 -1
  10. package/dist/index.cjs +1 -18
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +0 -6
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.mts +0 -6
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +0 -4
  17. package/dist/index.mjs.map +1 -1
  18. package/package.json +1 -1
  19. package/dist/errorNormalization.cjs +0 -84
  20. package/dist/errorNormalization.cjs.map +0 -1
  21. package/dist/errorNormalization.d.cts +0 -56
  22. package/dist/errorNormalization.d.cts.map +0 -1
  23. package/dist/errorNormalization.d.mts +0 -56
  24. package/dist/errorNormalization.d.mts.map +0 -1
  25. package/dist/errorNormalization.mjs +0 -78
  26. package/dist/errorNormalization.mjs.map +0 -1
  27. package/dist/providerAvailability.cjs +0 -100
  28. package/dist/providerAvailability.cjs.map +0 -1
  29. package/dist/providerAvailability.d.cts +0 -74
  30. package/dist/providerAvailability.d.cts.map +0 -1
  31. package/dist/providerAvailability.d.mts +0 -74
  32. package/dist/providerAvailability.d.mts.map +0 -1
  33. package/dist/providerAvailability.mjs +0 -93
  34. package/dist/providerAvailability.mjs.map +0 -1
  35. package/dist/quoteClassification.cjs +0 -44
  36. package/dist/quoteClassification.cjs.map +0 -1
  37. package/dist/quoteClassification.d.cts +0 -33
  38. package/dist/quoteClassification.d.cts.map +0 -1
  39. package/dist/quoteClassification.d.mts +0 -33
  40. package/dist/quoteClassification.d.mts.map +0 -1
  41. package/dist/quoteClassification.mjs +0 -38
  42. package/dist/quoteClassification.mjs.map +0 -1
  43. package/dist/quoteSelection.cjs +0 -154
  44. package/dist/quoteSelection.cjs.map +0 -1
  45. package/dist/quoteSelection.d.cts +0 -93
  46. package/dist/quoteSelection.d.cts.map +0 -1
  47. package/dist/quoteSelection.d.mts +0 -93
  48. package/dist/quoteSelection.d.mts.map +0 -1
  49. package/dist/quoteSelection.mjs +0 -148
  50. package/dist/quoteSelection.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -7,22 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ### Added
11
-
12
- - Add pure quote-selection helpers `getSmartSelectedQuote` and `fitsProviderLimits`, the amount validator `validateBuyAmount`, and a `BuyAmountValidation` type so headless-buy consumers can share the controller's provider-agnostic quote ranking (`preferredProviderIds` then reliability then price then first surviving candidate), scope-aware in-app filtering, and per-provider fiat-limit enforcement instead of re-deriving them ([#9414](https://github.com/MetaMask/core/pull/9414))
13
- - Add pure provider-availability helpers `providerServesAsset`, `getProvidersServingAsset`, `regionHasProviderForAsset`, and `isFiatDepositAvailable` so headless-buy consumers can share the controller's case-insensitive CAIP-19 asset matching and scope-aware region/availability gating instead of re-deriving it, keeping the two from disagreeing ([#9409](https://github.com/MetaMask/core/pull/9409))
14
- - Add pure quote-classification helpers `isExternalBrowserQuote`, `isCustomActionQuote`, and `isInAppOnlyQuote` so consumers can share the controller's in-app-vs-external browser-mode classification without owning host redirect/deeplink concerns ([#9409](https://github.com/MetaMask/core/pull/9409))
15
- - Add pure error-normalization helpers `getErrorMessage`, `extractExplicitTypedError`, and `normalizeToTypedError` (with a `TypedError<Code>` type) so consumers can share error-shape extraction while keeping their own error-code taxonomy ([#9409](https://github.com/MetaMask/core/pull/9409))
16
-
17
- ### Changed
18
-
19
- - `RampsController.getQuotes` now derives its provider-widening decision from the `getProviderScope` scope (`off` stays native-only; `in-app`/`all` widen) rather than the `restrictToKnownOrNativeProviders` flag, and picks the widened auto-selected quote via the shared `getSmartSelectedQuote`, feeding in the user's completed-order provider preference so a returning user's previously-used provider is preferred over the reliability/price winner ([#9414](https://github.com/MetaMask/core/pull/9414))
20
- - `RampsController` now derives its internal region provider-asset matching and quote in-app/custom-action/external filtering from the shared `providerAvailability` and `quoteClassification` helpers, so the exposed helpers stay behaviourally identical to the controller's own selection ([#9409](https://github.com/MetaMask/core/pull/9409))
21
-
22
- ### Deprecated
23
-
24
- - **`RampsController.getQuotes`'s `restrictToKnownOrNativeProviders` option is deprecated** in favor of provider-class scope (`getProviderScope`): `off` keeps native-only auto-selection and `in-app`/`all` widen, so the flag is redundant. It is still honored for one release (like `autoSelectProvider`, it routes a no-`providers` request through the gated path) and will be removed in a later major ([#9414](https://github.com/MetaMask/core/pull/9414))
25
-
26
10
  ## [15.1.0]
27
11
 
28
12
  ### Added
@@ -15,8 +15,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.RampsController = exports.getInternalOrderCode = exports.normalizeProviderCode = exports.getDefaultRampsControllerState = exports.RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS = exports.controllerName = void 0;
16
16
  const base_controller_1 = require("@metamask/base-controller");
17
17
  const controller_utils_1 = require("@metamask/controller-utils");
18
- const providerAvailability_1 = require("./providerAvailability.cjs");
19
- const quoteSelection_1 = require("./quoteSelection.cjs");
20
18
  const rampsErrorCodes_1 = require("./rampsErrorCodes.cjs");
21
19
  const RampsService_1 = require("./RampsService.cjs");
22
20
  const RequestCache_1 = require("./RequestCache.cjs");
@@ -993,17 +991,11 @@ class RampsController extends base_controller_1.BaseController {
993
991
  * during auto-selection, in priority order (e.g. derived by the caller
994
992
  * from completed-order history). Only used when `autoSelectProvider` is
995
993
  * true and `providers` is omitted.
996
- * @param options.restrictToKnownOrNativeProviders - **Deprecated** (still
997
- * honored for one release). Headless-buy v0 gating: when true,
998
- * auto-selection resolves only a native provider, and an explicitly passed
999
- * `providers` list is filtered to those supporting the region and asset; if
1000
- * nothing qualifies, `getQuotes` returns an empty response instead of
1001
- * quoting other providers. Provider-class scope (`getProviderScope`) is now
1002
- * the gate (`off` stays native-only; `in-app`/`all` widen), so this flag is
1003
- * redundant and will be removed in a later major. Like `autoSelectProvider`,
1004
- * it still routes a no-`providers` request through the gated path so
1005
- * existing callers keep working; new callers should rely on the scope
1006
- * instead of passing this flag.
994
+ * @param options.restrictToKnownOrNativeProviders - Headless-buy v0 gating. When
995
+ * true, auto-selection resolves only a native provider, and an explicitly
996
+ * passed `providers` list is filtered to those supporting the region and
997
+ * asset. If nothing qualifies, `getQuotes` returns an empty response
998
+ * instead of quoting other providers.
1007
999
  * @param options.redirectUrl - Optional redirect URL after order completion.
1008
1000
  * @param options.action - The ramp action type. Defaults to 'buy'.
1009
1001
  * @param options.forceRefresh - Whether to bypass cache.
@@ -1024,24 +1016,17 @@ class RampsController extends base_controller_1.BaseController {
1024
1016
  if (normalizedAssetIdForValidation === '') {
1025
1017
  throw new Error('assetId is required.');
1026
1018
  }
1027
- // Provider-class scope is the gate (P2.M8): `off` keeps native-only
1028
- // auto-selection (the kill switch); `in-app`/`all` widen the auto-selection
1029
- // path to every supporting provider and pick the best quote from the
1030
- // results (in-app vs external is only knowable per-quote via
1031
- // `buyWidget.browser`). Only the auto-select path that MM Pay's
1019
+ // When a non-`off` provider scope is active, widen the native-only
1020
+ // auto-selection path to every supporting provider and pick the best in-app
1021
+ // quote from the results (in-app vs external is only knowable per-quote via
1022
+ // `buyWidget.browser`). Only the auto-select/restrict path that MM Pay's
1032
1023
  // `getRampsQuote` uses is affected; explicit-`providers` callers and the
1033
1024
  // plain all-provider path are untouched.
1034
1025
  const providerScope = __classPrivateFieldGet(this, _RampsController_getProviderScope, "f").call(this);
1035
- const scopeWidens = providerScope !== 'off';
1036
- // The auto-select entry path. `restrictToKnownOrNativeProviders` is
1037
- // `@deprecated` (P2.M8) but still honored here: like `autoSelectProvider`,
1038
- // it routes a no-explicit-`providers` request through the resolved/gated
1039
- // path, so existing callers (TPC `getRampsQuote`) are unaffected until the
1040
- // option is removed in a later major.
1041
- const usesAutoSelectPath = !options.providers &&
1026
+ const widenToInAppProviders = providerScope !== 'off' &&
1027
+ !options.providers &&
1042
1028
  (options.autoSelectProvider === true ||
1043
1029
  options.restrictToKnownOrNativeProviders === true);
1044
- const widenToInAppProviders = scopeWidens && usesAutoSelectPath;
1045
1030
  let providersToUse;
1046
1031
  let inAppProviderCatalog = this.state.providers.data;
1047
1032
  if (options.providers) {
@@ -1098,8 +1083,7 @@ class RampsController extends base_controller_1.BaseController {
1098
1083
  // `restrictToKnownOrNativeProviders`), and an empty supporting set must not
1099
1084
  // fall through to unfiltered quotes from providers that do not support the
1100
1085
  // asset.
1101
- if ((widenToInAppProviders ||
1102
- options.restrictToKnownOrNativeProviders === true) &&
1086
+ if ((options.restrictToKnownOrNativeProviders || widenToInAppProviders) &&
1103
1087
  providersToUse.length === 0) {
1104
1088
  return { success: [], sorted: [], error: [], customActions: [] };
1105
1089
  }
@@ -1914,13 +1898,62 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
1914
1898
  state.userRegion = userRegion;
1915
1899
  });
1916
1900
  }, _RampsController_pickInAppQuote = function _RampsController_pickInAppQuote(response, { scope, amount, fiat, providers, }) {
1917
- return (0, quoteSelection_1.getSmartSelectedQuote)(response, {
1918
- scope,
1919
- amount,
1920
- fiat,
1921
- providers,
1922
- preferredProviderIds: __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_getPreferredProviderIdsFromOrders).call(this),
1923
- });
1901
+ const providerByCode = new Map(providers.map((provider) => [
1902
+ normalizeProviderCode(provider.id),
1903
+ provider,
1904
+ ]));
1905
+ const customActionProviderCodes = new Set(response.customActions.map((action) => normalizeProviderCode(action.buy.providerId)));
1906
+ const fitsProviderLimits = (quote) => {
1907
+ const provider = providerByCode.get(normalizeProviderCode(quote.provider));
1908
+ const limit = provider?.limits?.fiat?.[fiat]?.[quote.quote.paymentMethod];
1909
+ if (!limit) {
1910
+ // No published limits for this provider/payment method: treat as
1911
+ // eligible and let the provider enforce limits at checkout.
1912
+ return true;
1913
+ }
1914
+ return amount >= limit.minAmount && amount <= limit.maxAmount;
1915
+ };
1916
+ const isEligible = (quote) => {
1917
+ // `all` (Phase 2) skips the in-app-only exclusions; both scopes still
1918
+ // enforce provider limits up front.
1919
+ if (scope !== 'all') {
1920
+ const providerCode = normalizeProviderCode(quote.provider);
1921
+ if (customActionProviderCodes.has(providerCode)) {
1922
+ return false;
1923
+ }
1924
+ // Defensive: the wire may carry an inline `isCustomAction` flag that is
1925
+ // absent from the published `Quote` type.
1926
+ if (quote.quote.isCustomAction === true) {
1927
+ return false;
1928
+ }
1929
+ if (quote.quote.buyWidget?.browser === 'IN_APP_OS_BROWSER') {
1930
+ return false;
1931
+ }
1932
+ }
1933
+ return fitsProviderLimits(quote);
1934
+ };
1935
+ const candidates = response.success.filter(isEligible);
1936
+ if (candidates.length === 0) {
1937
+ return undefined;
1938
+ }
1939
+ const candidateByCode = new Map(candidates.map((quote) => [normalizeProviderCode(quote.provider), quote]));
1940
+ const pickBySortOrder = (sortBy) => {
1941
+ const order = response.sorted.find((entry) => entry.sortBy === sortBy)?.ids;
1942
+ if (!order) {
1943
+ return undefined;
1944
+ }
1945
+ for (const providerId of order) {
1946
+ const match = candidateByCode.get(normalizeProviderCode(providerId));
1947
+ if (match) {
1948
+ return match;
1949
+ }
1950
+ }
1951
+ return undefined;
1952
+ };
1953
+ // Reliability first, then price, then the first surviving candidate.
1954
+ return (pickBySortOrder('reliability') ??
1955
+ pickBySortOrder('price') ??
1956
+ candidates[0]);
1924
1957
  }, _RampsController_getSupportingProvidersForRegion =
1925
1958
  /**
1926
1959
  * Returns the region's providers that support the given asset, plus the full
@@ -1944,10 +1977,18 @@ async function _RampsController_getSupportingProvidersForRegion({ assetId, regio
1944
1977
  else {
1945
1978
  ({ providers } = await this.getProviders(normalizedRegion));
1946
1979
  }
1947
- // Case-insensitive CAIP-19 matching is shared with headless-buy consumers
1948
- // via `getProvidersServingAsset`, so the controller and the UI region gate
1949
- // cannot disagree about which providers serve the asset.
1950
- const supporting = (0, providerAvailability_1.getProvidersServingAsset)(providers, assetId);
1980
+ // EVM CAIP-19 asset IDs may arrive checksummed or lowercased, and the
1981
+ // providers API returns both forms, so match case-insensitively on both
1982
+ // sides. Only the lowercased forms are compared (the original IDs are never
1983
+ // returned), so case-sensitive non-EVM asset IDs are not corrupted.
1984
+ const normalizedAssetId = assetId.toLowerCase();
1985
+ const supporting = providers.filter((provider) => {
1986
+ const map = provider?.supportedCryptoCurrencies;
1987
+ if (!map) {
1988
+ return false;
1989
+ }
1990
+ return Object.keys(map).some((key) => key.toLowerCase() === normalizedAssetId);
1991
+ });
1951
1992
  return { supporting, all: providers };
1952
1993
  }, _RampsController_filterProviderIdsBySupport =
1953
1994
  /**