@metamask-previews/ramps-controller 14.0.0-preview-e15374a5d → 14.1.0-preview-d3cc77e

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.
@@ -10,7 +10,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
12
  };
13
- var _RampsController_instances, _RampsController_requestCacheTTL, _RampsController_requestCacheMaxSize, _RampsController_pendingRequests, _RampsController_pendingResourceCount, _RampsController_pendingResourceGeneration, _RampsController_orderPollingMeta, _RampsController_orderPollingTimer, _RampsController_isPolling, _RampsController_initPromise, _RampsController_clearPendingResourceCountForDependentResources, _RampsController_abortDependentRequests, _RampsController_mutateRequests, _RampsController_removeRequestState, _RampsController_cleanupState, _RampsController_requireRegion, _RampsController_isRegionCurrent, _RampsController_isTokenCurrent, _RampsController_isProviderCurrent, _RampsController_updateResourceField, _RampsController_setResourceLoading, _RampsController_setResourceError, _RampsController_updateRequestState, _RampsController_runInit, _RampsController_refreshOrder, _RampsController_pollPendingOrders, _RampsController_syncTransakAuthOnError, _RampsController_getNormalizedTransakError;
13
+ var _RampsController_instances, _RampsController_requestCacheTTL, _RampsController_requestCacheMaxSize, _RampsController_pendingRequests, _RampsController_pendingResourceCount, _RampsController_pendingResourceGeneration, _RampsController_orderPollingMeta, _RampsController_orderPollingTimer, _RampsController_isPolling, _RampsController_initPromise, _RampsController_clearPendingResourceCountForDependentResources, _RampsController_abortDependentRequests, _RampsController_mutateRequests, _RampsController_removeRequestState, _RampsController_cleanupState, _RampsController_requireRegion, _RampsController_isRegionCurrent, _RampsController_isTokenCurrent, _RampsController_isProviderCurrent, _RampsController_updateResourceField, _RampsController_setResourceLoading, _RampsController_setResourceError, _RampsController_updateRequestState, _RampsController_runInit, _RampsController_getSupportingProvidersForRegion, _RampsController_filterProviderIdsBySupport, _RampsController_resolveProviderIdsForQuote, _RampsController_getPreferredProviderIdsFromOrders, _RampsController_refreshOrder, _RampsController_pollPendingOrders, _RampsController_syncTransakAuthOnError, _RampsController_getNormalizedTransakError;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.RampsController = exports.normalizeProviderCode = exports.getDefaultRampsControllerState = exports.RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS = exports.controllerName = void 0;
16
16
  const base_controller_1 = require("@metamask/base-controller");
@@ -953,6 +953,18 @@ class RampsController extends base_controller_1.BaseController {
953
953
  * @param options.walletAddress - The destination wallet address.
954
954
  * @param options.paymentMethods - Array of payment method IDs. If not provided, uses paymentMethods from state.
955
955
  * @param options.providers - Optional provider IDs to filter quotes.
956
+ * @param options.autoSelectProvider - When true and `providers` is omitted,
957
+ * resolves a provider that supports `assetId` for this request only (no
958
+ * state mutation). Ignored when `providers` is passed.
959
+ * @param options.preferredProviderIds - Optional provider IDs to prefer
960
+ * during auto-selection, in priority order (e.g. derived by the caller
961
+ * from completed-order history). Only used when `autoSelectProvider` is
962
+ * true and `providers` is omitted.
963
+ * @param options.restrictToKnownOrNativeProviders - Headless-buy v0 gating. When
964
+ * true, auto-selection resolves only a native provider, and an explicitly
965
+ * passed `providers` list is filtered to those supporting the region and
966
+ * asset. If nothing qualifies, `getQuotes` returns an empty response
967
+ * instead of quoting other providers.
956
968
  * @param options.redirectUrl - Optional redirect URL after order completion.
957
969
  * @param options.action - The ramp action type. Defaults to 'buy'.
958
970
  * @param options.forceRefresh - Whether to bypass cache.
@@ -964,8 +976,6 @@ class RampsController extends base_controller_1.BaseController {
964
976
  const fiatToUse = options.fiat ?? this.state.userRegion?.country?.currency;
965
977
  const paymentMethodsToUse = options.paymentMethods ??
966
978
  this.state.paymentMethods.data.map((pm) => pm.id);
967
- const providersToUse = options.providers ??
968
- this.state.providers.data.map((provider) => provider.id);
969
979
  const action = options.action ?? 'buy';
970
980
  const assetIdToUse = options.assetId ?? this.state.tokens.selected?.assetId;
971
981
  if (!fiatToUse) {
@@ -975,6 +985,31 @@ class RampsController extends base_controller_1.BaseController {
975
985
  if (normalizedAssetIdForValidation === '') {
976
986
  throw new Error('assetId is required.');
977
987
  }
988
+ let providersToUse;
989
+ if (options.providers) {
990
+ providersToUse = options.restrictToKnownOrNativeProviders
991
+ ? await __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_filterProviderIdsBySupport).call(this, {
992
+ providerIds: options.providers,
993
+ assetId: normalizedAssetIdForValidation,
994
+ region: regionToUse,
995
+ })
996
+ : options.providers;
997
+ }
998
+ else if (options.autoSelectProvider ||
999
+ options.restrictToKnownOrNativeProviders) {
1000
+ // The restriction flag implies resolution: it must narrow the provider
1001
+ // set even when `autoSelectProvider` was not explicitly passed, otherwise
1002
+ // it would be silently ignored and every provider quoted.
1003
+ providersToUse = await __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_resolveProviderIdsForQuote).call(this, {
1004
+ assetId: normalizedAssetIdForValidation,
1005
+ region: regionToUse,
1006
+ preferredProviderIds: options.preferredProviderIds,
1007
+ restrictToKnownOrNative: options.restrictToKnownOrNativeProviders,
1008
+ });
1009
+ }
1010
+ else {
1011
+ providersToUse = this.state.providers.data.map((provider) => provider.id);
1012
+ }
978
1013
  if (!paymentMethodsToUse ||
979
1014
  paymentMethodsToUse.length === 0 ||
980
1015
  paymentMethodsToUse.some((pm) => pm.trim() === '')) {
@@ -986,6 +1021,14 @@ class RampsController extends base_controller_1.BaseController {
986
1021
  if (!options.walletAddress || options.walletAddress.trim() === '') {
987
1022
  throw new Error('walletAddress is required.');
988
1023
  }
1024
+ // Under headless-buy gating, an empty resolved provider list means no
1025
+ // eligible (native/supporting) provider exists. Return an empty response
1026
+ // rather than passing `[]` to the service, which omits the provider filter
1027
+ // and would quote every provider.
1028
+ if (options.restrictToKnownOrNativeProviders &&
1029
+ providersToUse.length === 0) {
1030
+ return { success: [], sorted: [], error: [], customActions: [] };
1031
+ }
989
1032
  const normalizedRegion = regionToUse.toLowerCase().trim();
990
1033
  const normalizedFiat = fiatToUse.toLowerCase().trim();
991
1034
  const normalizedAssetId = normalizedAssetIdForValidation;
@@ -1727,6 +1770,142 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
1727
1770
  throw new Error('Failed to fetch geolocation. Cannot initialize controller without valid region information.');
1728
1771
  }
1729
1772
  await this.setUserRegion(regionCode, options);
1773
+ }, _RampsController_getSupportingProvidersForRegion =
1774
+ /**
1775
+ * Returns the region's providers that support the given asset, plus the full
1776
+ * region provider list. Uses cached providers only when the request targets
1777
+ * the current region; otherwise fetches for the requested region, since
1778
+ * `getProviders` does not persist results for a non-current region. Does not
1779
+ * mutate state.
1780
+ *
1781
+ * @param options - The options.
1782
+ * @param options.assetId - CAIP-19 asset type identifier to resolve for.
1783
+ * @param options.region - Region to resolve providers for.
1784
+ * @returns The supporting providers and the full region provider list.
1785
+ */
1786
+ async function _RampsController_getSupportingProvidersForRegion({ assetId, region, }) {
1787
+ const normalizedRegion = region.toLowerCase().trim();
1788
+ let providers;
1789
+ if (__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_isRegionCurrent).call(this, normalizedRegion) &&
1790
+ this.state.providers.data.length > 0) {
1791
+ providers = this.state.providers.data;
1792
+ }
1793
+ else {
1794
+ ({ providers } = await this.getProviders(normalizedRegion));
1795
+ }
1796
+ // EVM CAIP-19 asset IDs may arrive checksummed or lowercased, and the
1797
+ // providers API returns both forms, so match case-insensitively on both
1798
+ // sides. Only the lowercased forms are compared (the original IDs are never
1799
+ // returned), so case-sensitive non-EVM asset IDs are not corrupted.
1800
+ const normalizedAssetId = assetId.toLowerCase();
1801
+ const supporting = providers.filter((provider) => {
1802
+ const map = provider?.supportedCryptoCurrencies;
1803
+ if (!map) {
1804
+ return false;
1805
+ }
1806
+ return Object.keys(map).some((key) => key.toLowerCase() === normalizedAssetId);
1807
+ });
1808
+ return { supporting, all: providers };
1809
+ }, _RampsController_filterProviderIdsBySupport =
1810
+ /**
1811
+ * Filters an explicitly-requested provider ID list down to those that support
1812
+ * the asset in the region. Used for headless-buy gating so an explicitly
1813
+ * passed provider that cannot serve the region/asset yields no providers
1814
+ * rather than being trusted blindly.
1815
+ *
1816
+ * @param options - The options.
1817
+ * @param options.providerIds - Explicitly requested provider IDs.
1818
+ * @param options.assetId - CAIP-19 asset type identifier to resolve for.
1819
+ * @param options.region - Region to resolve providers for.
1820
+ * @returns The subset of `providerIds` supporting the asset in the region.
1821
+ */
1822
+ async function _RampsController_filterProviderIdsBySupport({ providerIds, assetId, region, }) {
1823
+ const { supporting } = await __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_getSupportingProvidersForRegion).call(this, {
1824
+ assetId,
1825
+ region,
1826
+ });
1827
+ const supportingIds = new Set(supporting.map((provider) => provider.id));
1828
+ return providerIds.filter((id) => supportingIds.has(id));
1829
+ }, _RampsController_resolveProviderIdsForQuote =
1830
+ /**
1831
+ * Resolves the provider IDs to use for a single quote request, scoped to the
1832
+ * given asset and region. Does not mutate `providers.selected` or any other
1833
+ * state.
1834
+ *
1835
+ * Resolves against the region's supporting providers using this precedence:
1836
+ * 1. The currently selected provider, if it is in the supporting set.
1837
+ * 2. The first preferred provider that supports the asset, where the
1838
+ * preference is taken from `preferredProviderIds` when supplied, otherwise
1839
+ * derived from the user's completed-order history (most recent first).
1840
+ * This takes priority over Transak Native to preserve an existing KYC
1841
+ * relationship.
1842
+ * 3. A native provider (e.g. Transak Native).
1843
+ * 4. The first supporting provider — unless `restrictToKnownOrNative` is set, in
1844
+ * which case no further provider is introduced and nothing is returned.
1845
+ *
1846
+ * When `restrictToKnownOrNative` is unset and no provider supports the asset, falls
1847
+ * back to all known provider IDs so the request behaves as if no
1848
+ * auto-selection occurred.
1849
+ *
1850
+ * @param options - The options.
1851
+ * @param options.assetId - CAIP-19 asset type identifier to resolve for.
1852
+ * @param options.region - Region to resolve providers for.
1853
+ * @param options.preferredProviderIds - Provider IDs to prefer, in order.
1854
+ * @param options.restrictToKnownOrNative - When true, resolve only a native provider
1855
+ * (or no providers when none supports the asset).
1856
+ * @returns Provider IDs for this request only.
1857
+ */
1858
+ async function _RampsController_resolveProviderIdsForQuote({ assetId, region, preferredProviderIds, restrictToKnownOrNative, }) {
1859
+ const { supporting, all } = await __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_getSupportingProvidersForRegion).call(this, {
1860
+ assetId,
1861
+ region,
1862
+ });
1863
+ // When not restricted and nothing supports the asset, behave as if no
1864
+ // auto-selection occurred (quote against all known providers).
1865
+ if (!restrictToKnownOrNative && supporting.length === 0) {
1866
+ return all.map((provider) => provider.id);
1867
+ }
1868
+ // 1. The currently selected provider, if it supports the asset.
1869
+ const { selected } = this.state.providers;
1870
+ if (selected &&
1871
+ supporting.some((provider) => provider.id === selected.id)) {
1872
+ return [selected.id];
1873
+ }
1874
+ // 2. A provider the user has transacted with before — from
1875
+ // `preferredProviderIds` when supplied, otherwise completed-order
1876
+ // history. Takes priority over Transak Native to preserve an existing
1877
+ // KYC relationship and avoid churn.
1878
+ const preferred = preferredProviderIds ?? __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_getPreferredProviderIdsFromOrders).call(this);
1879
+ for (const preferredId of preferred) {
1880
+ const match = supporting.find((provider) => provider.id === preferredId);
1881
+ if (match) {
1882
+ return [match.id];
1883
+ }
1884
+ }
1885
+ // 3. A native provider (e.g. Transak Native).
1886
+ const nativeProvider = supporting.find((provider) => provider.type === 'native');
1887
+ if (nativeProvider) {
1888
+ return [nativeProvider.id];
1889
+ }
1890
+ // 4. Fallback. Under headless gating, introduce no other provider — return
1891
+ // nothing so the caller surfaces an "unavailable" state. Otherwise the
1892
+ // aggregator and all other providers are treated equally: first wins.
1893
+ if (restrictToKnownOrNative) {
1894
+ return [];
1895
+ }
1896
+ return [supporting[0].id];
1897
+ }, _RampsController_getPreferredProviderIdsFromOrders = function _RampsController_getPreferredProviderIdsFromOrders() {
1898
+ const orderedIds = [];
1899
+ const completedOrders = this.state.orders
1900
+ .filter((order) => order.status === RampsService_1.RampsOrderStatus.Completed && order.provider?.id)
1901
+ .sort((orderA, orderB) => orderB.createdAt - orderA.createdAt);
1902
+ for (const order of completedOrders) {
1903
+ const id = order.provider?.id;
1904
+ if (id && !orderedIds.includes(id)) {
1905
+ orderedIds.push(id);
1906
+ }
1907
+ }
1908
+ return orderedIds;
1730
1909
  }, _RampsController_refreshOrder =
1731
1910
  /**
1732
1911
  * Refreshes a single order via the V2 API and updates it in state.