@metamask/ramps-controller 7.1.0 → 8.0.0
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.
- package/CHANGELOG.md +9 -1
- package/dist/RampsController.cjs +35 -17
- package/dist/RampsController.cjs.map +1 -1
- package/dist/RampsController.d.cts +11 -10
- package/dist/RampsController.d.cts.map +1 -1
- package/dist/RampsController.d.mts +11 -10
- package/dist/RampsController.d.mts.map +1 -1
- package/dist/RampsController.mjs +35 -17
- package/dist/RampsController.mjs.map +1 -1
- package/dist/RampsService-method-action-types.cjs.map +1 -1
- package/dist/RampsService-method-action-types.d.cts +14 -2
- package/dist/RampsService-method-action-types.d.cts.map +1 -1
- package/dist/RampsService-method-action-types.d.mts +14 -2
- package/dist/RampsService-method-action-types.d.mts.map +1 -1
- package/dist/RampsService-method-action-types.mjs.map +1 -1
- package/dist/RampsService.cjs +28 -4
- package/dist/RampsService.cjs.map +1 -1
- package/dist/RampsService.d.cts +38 -7
- package/dist/RampsService.d.cts.map +1 -1
- package/dist/RampsService.d.mts +38 -7
- package/dist/RampsService.d.mts.map +1 -1
- package/dist/RampsService.mjs +28 -4
- package/dist/RampsService.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [8.0.0]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **BREAKING:** Quote filter param renamed from `provider` to `providers` array in `getQuotes()` and `RampsService.getQuotes()` ([#7892](https://github.com/MetaMask/core/pull/7892))
|
|
15
|
+
- **BREAKING:** Make `getWidgetUrl()` async to fetch the actual provider widget URL from the `buyURL` endpoint ([#7881](https://github.com/MetaMask/core/pull/7881))
|
|
16
|
+
|
|
10
17
|
## [7.1.0]
|
|
11
18
|
|
|
12
19
|
### Fixed
|
|
@@ -134,7 +141,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
134
141
|
- Add `OnRampService` for interacting with the OnRamp API
|
|
135
142
|
- Add geolocation detection via IP address lookup
|
|
136
143
|
|
|
137
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@
|
|
144
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@8.0.0...HEAD
|
|
145
|
+
[8.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@7.1.0...@metamask/ramps-controller@8.0.0
|
|
138
146
|
[7.1.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@7.0.0...@metamask/ramps-controller@7.1.0
|
|
139
147
|
[7.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@6.0.0...@metamask/ramps-controller@7.0.0
|
|
140
148
|
[6.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@5.1.0...@metamask/ramps-controller@6.0.0
|
package/dist/RampsController.cjs
CHANGED
|
@@ -34,6 +34,7 @@ exports.RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS = [
|
|
|
34
34
|
'RampsService:getProviders',
|
|
35
35
|
'RampsService:getPaymentMethods',
|
|
36
36
|
'RampsService:getQuotes',
|
|
37
|
+
'RampsService:getBuyWidgetUrl',
|
|
37
38
|
];
|
|
38
39
|
/**
|
|
39
40
|
* Default TTL for quotes requests (15 seconds).
|
|
@@ -774,7 +775,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
774
775
|
* @param options.amount - The amount (in fiat for buy, crypto for sell).
|
|
775
776
|
* @param options.walletAddress - The destination wallet address.
|
|
776
777
|
* @param options.paymentMethods - Array of payment method IDs. If not provided, uses paymentMethods from state.
|
|
777
|
-
* @param options.
|
|
778
|
+
* @param options.providers - Optional provider IDs to filter quotes.
|
|
778
779
|
* @param options.redirectUrl - Optional redirect URL after order completion.
|
|
779
780
|
* @param options.action - The ramp action type. Defaults to 'buy'.
|
|
780
781
|
* @param options.forceRefresh - Whether to bypass cache.
|
|
@@ -786,28 +787,34 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
786
787
|
const fiatToUse = options.fiat ?? this.state.userRegion?.country?.currency;
|
|
787
788
|
const paymentMethodsToUse = options.paymentMethods ??
|
|
788
789
|
this.state.paymentMethods.data.map((pm) => pm.id);
|
|
790
|
+
const providersToUse = options.providers ??
|
|
791
|
+
this.state.providers.data.map((provider) => provider.id);
|
|
789
792
|
const action = options.action ?? 'buy';
|
|
793
|
+
const assetIdToUse = options.assetId ?? this.state.tokens.selected?.assetId;
|
|
790
794
|
if (!regionToUse) {
|
|
791
795
|
throw new Error('Region is required. Either provide a region parameter or ensure userRegion is set in controller state.');
|
|
792
796
|
}
|
|
793
797
|
if (!fiatToUse) {
|
|
794
798
|
throw new Error('Fiat currency is required. Either provide a fiat parameter or ensure userRegion is set in controller state.');
|
|
795
799
|
}
|
|
796
|
-
|
|
800
|
+
const normalizedAssetIdForValidation = (assetIdToUse ?? '').trim();
|
|
801
|
+
if (normalizedAssetIdForValidation === '') {
|
|
802
|
+
throw new Error('assetId is required.');
|
|
803
|
+
}
|
|
804
|
+
if (!paymentMethodsToUse ||
|
|
805
|
+
paymentMethodsToUse.length === 0 ||
|
|
806
|
+
paymentMethodsToUse.some((pm) => pm.trim() === '')) {
|
|
797
807
|
throw new Error('Payment methods are required. Either provide paymentMethods parameter or ensure paymentMethods are set in controller state.');
|
|
798
808
|
}
|
|
799
809
|
if (options.amount <= 0 || !Number.isFinite(options.amount)) {
|
|
800
810
|
throw new Error('Amount must be a positive finite number.');
|
|
801
811
|
}
|
|
802
|
-
if (!options.assetId || options.assetId.trim() === '') {
|
|
803
|
-
throw new Error('assetId is required.');
|
|
804
|
-
}
|
|
805
812
|
if (!options.walletAddress || options.walletAddress.trim() === '') {
|
|
806
813
|
throw new Error('walletAddress is required.');
|
|
807
814
|
}
|
|
808
815
|
const normalizedRegion = regionToUse.toLowerCase().trim();
|
|
809
816
|
const normalizedFiat = fiatToUse.toLowerCase().trim();
|
|
810
|
-
const normalizedAssetId =
|
|
817
|
+
const normalizedAssetId = normalizedAssetIdForValidation;
|
|
811
818
|
const normalizedWalletAddress = options.walletAddress.trim();
|
|
812
819
|
const cacheKey = (0, RequestCache_1.createCacheKey)('getQuotes', [
|
|
813
820
|
normalizedRegion,
|
|
@@ -816,7 +823,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
816
823
|
options.amount,
|
|
817
824
|
normalizedWalletAddress,
|
|
818
825
|
[...paymentMethodsToUse].sort().join(','),
|
|
819
|
-
|
|
826
|
+
[...providersToUse].sort().join(','),
|
|
820
827
|
options.redirectUrl,
|
|
821
828
|
action,
|
|
822
829
|
]);
|
|
@@ -827,7 +834,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
827
834
|
amount: options.amount,
|
|
828
835
|
walletAddress: normalizedWalletAddress,
|
|
829
836
|
paymentMethods: paymentMethodsToUse,
|
|
830
|
-
|
|
837
|
+
providers: providersToUse,
|
|
831
838
|
redirectUrl: options.redirectUrl,
|
|
832
839
|
action,
|
|
833
840
|
};
|
|
@@ -890,7 +897,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
890
897
|
walletAddress: options.walletAddress,
|
|
891
898
|
redirectUrl: options.redirectUrl,
|
|
892
899
|
paymentMethods: [paymentMethod.id],
|
|
893
|
-
|
|
900
|
+
providers: [provider.id],
|
|
894
901
|
forceRefresh: true,
|
|
895
902
|
}).then((response) => {
|
|
896
903
|
// Auto-select logic: only when exactly one quote is returned
|
|
@@ -949,14 +956,26 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
949
956
|
super.destroy();
|
|
950
957
|
}
|
|
951
958
|
/**
|
|
952
|
-
*
|
|
953
|
-
*
|
|
959
|
+
* Fetches the widget URL from a quote for redirect providers.
|
|
960
|
+
* Makes a request to the buyURL endpoint via the RampsService to get the
|
|
961
|
+
* actual provider widget URL, using the injected fetch and retry policy.
|
|
954
962
|
*
|
|
955
|
-
* @param quote - The quote to
|
|
956
|
-
* @returns
|
|
963
|
+
* @param quote - The quote to fetch the widget URL from.
|
|
964
|
+
* @returns Promise resolving to the widget URL string, or null if not available.
|
|
957
965
|
*/
|
|
958
|
-
getWidgetUrl(quote) {
|
|
959
|
-
|
|
966
|
+
async getWidgetUrl(quote) {
|
|
967
|
+
const buyUrl = quote.quote?.buyURL;
|
|
968
|
+
if (!buyUrl) {
|
|
969
|
+
return null;
|
|
970
|
+
}
|
|
971
|
+
try {
|
|
972
|
+
const buyWidget = await this.messenger.call('RampsService:getBuyWidgetUrl', buyUrl);
|
|
973
|
+
return buyWidget.url ?? null;
|
|
974
|
+
}
|
|
975
|
+
catch (error) {
|
|
976
|
+
console.error('Error fetching widget URL:', error);
|
|
977
|
+
return null;
|
|
978
|
+
}
|
|
960
979
|
}
|
|
961
980
|
}
|
|
962
981
|
exports.RampsController = RampsController;
|
|
@@ -1017,8 +1036,7 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
|
|
|
1017
1036
|
const keys = Object.keys(requests);
|
|
1018
1037
|
for (const key of keys) {
|
|
1019
1038
|
const entry = requests[key];
|
|
1020
|
-
if (entry &&
|
|
1021
|
-
entry.status === RequestCache_1.RequestStatus.SUCCESS &&
|
|
1039
|
+
if (entry?.status === RequestCache_1.RequestStatus.SUCCESS &&
|
|
1022
1040
|
(0, RequestCache_1.isCacheExpired)(entry, ttl)) {
|
|
1023
1041
|
delete requests[key];
|
|
1024
1042
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RampsController.cjs","sourceRoot":"","sources":["../src/RampsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\n\nimport type {\n Country,\n TokensResponse,\n Provider,\n State,\n RampAction,\n PaymentMethod,\n PaymentMethodsResponse,\n QuotesResponse,\n Quote,\n GetQuotesParams,\n RampsToken,\n RampsServiceActions,\n} from './RampsService';\nimport type {\n RampsServiceGetGeolocationAction,\n RampsServiceGetCountriesAction,\n RampsServiceGetTokensAction,\n RampsServiceGetProvidersAction,\n RampsServiceGetPaymentMethodsAction,\n RampsServiceGetQuotesAction,\n} from './RampsService-method-action-types';\nimport type {\n RequestCache as RequestCacheType,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n ResourceType,\n} from './RequestCache';\nimport {\n DEFAULT_REQUEST_CACHE_TTL,\n DEFAULT_REQUEST_CACHE_MAX_SIZE,\n createCacheKey,\n isCacheExpired,\n createLoadingState,\n createSuccessState,\n createErrorState,\n RequestStatus,\n} from './RequestCache';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link RampsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'RampsController';\n\n/**\n * RampsService action types that RampsController calls via the messenger.\n * Any host (e.g. mobile) that creates a RampsController messenger must delegate\n * these actions from the root messenger so the controller can function.\n */\nexport const RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS: readonly RampsServiceActions['type'][] =\n [\n 'RampsService:getGeolocation',\n 'RampsService:getCountries',\n 'RampsService:getTokens',\n 'RampsService:getProviders',\n 'RampsService:getPaymentMethods',\n 'RampsService:getQuotes',\n ];\n\n/**\n * Default TTL for quotes requests (15 seconds).\n * Quotes are time-sensitive and should have a shorter cache duration.\n */\nconst DEFAULT_QUOTES_TTL = 15000;\n\n// === STATE ===\n\n/**\n * Represents the user's selected region with full country and state objects.\n */\nexport type UserRegion = {\n /**\n * The country object for the selected region.\n */\n country: Country;\n /**\n * The state object if a state was selected, null if only country was selected.\n */\n state: State | null;\n /**\n * The region code string (e.g., \"us-ut\" or \"fr\") used for API calls.\n */\n regionCode: string;\n};\n\n/**\n * Generic type for resource state that bundles data with loading/error states.\n *\n * @template TData - The type of the resource data\n * @template TSelected - The type of the selected item (defaults to null for resources without selection)\n */\nexport type ResourceState<TData, TSelected = null> = {\n /**\n * The resource data.\n */\n data: TData;\n /**\n * The currently selected item, or null if none selected.\n */\n selected: TSelected;\n /**\n * Whether the resource is currently being fetched.\n */\n isLoading: boolean;\n /**\n * Error message if the fetch failed, or null.\n */\n error: string | null;\n};\n\n/**\n * Describes the shape of the state object for {@link RampsController}.\n */\nexport type RampsControllerState = {\n /**\n * The user's region (full country and state objects).\n * Initially set via geolocation fetch, but can be manually changed by the user.\n */\n userRegion: UserRegion | null;\n /**\n * Countries resource state with data, loading, and error.\n * Data contains the list of countries available for ramp actions.\n */\n countries: ResourceState<Country[]>;\n /**\n * Providers resource state with data, selected, loading, and error.\n * Data contains the list of providers available for the current region.\n */\n providers: ResourceState<Provider[], Provider | null>;\n /**\n * Tokens resource state with data, selected, loading, and error.\n * Data contains topTokens and allTokens arrays.\n */\n tokens: ResourceState<TokensResponse | null, RampsToken | null>;\n /**\n * Payment methods resource state with data, selected, loading, and error.\n * Data contains payment methods filtered by region, fiat, asset, and provider.\n */\n paymentMethods: ResourceState<PaymentMethod[], PaymentMethod | null>;\n /**\n * Quotes resource state with data, selected, loading, and error.\n * Data contains quotes from multiple providers for the given parameters.\n * Selected contains the currently selected quote for the user.\n */\n quotes: ResourceState<QuotesResponse | null, Quote | null>;\n /**\n * Cache of request states, keyed by cache key.\n * This stores loading, success, and error states for API requests.\n */\n requests: RequestCacheType;\n};\n\n/**\n * The metadata for each property in {@link RampsControllerState}.\n */\nconst rampsControllerMetadata = {\n userRegion: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n countries: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n providers: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n tokens: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n paymentMethods: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n quotes: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: false,\n usedInUi: true,\n },\n requests: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: false,\n usedInUi: true,\n },\n} satisfies StateMetadata<RampsControllerState>;\n\n/**\n * Creates a default resource state object.\n *\n * @template TData - The type of the resource data.\n * @template TSelected - The type of the selected item.\n * @param data - The initial data value.\n * @param selected - The initial selected value.\n * @returns A ResourceState object with default loading and error values.\n */\nfunction createDefaultResourceState<TData, TSelected = null>(\n data: TData,\n selected: TSelected = null as TSelected,\n): ResourceState<TData, TSelected> {\n return {\n data,\n selected,\n isLoading: false,\n error: null,\n };\n}\n\n/**\n * Constructs the default {@link RampsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link RampsController} state.\n */\nexport function getDefaultRampsControllerState(): RampsControllerState {\n return {\n userRegion: null,\n countries: createDefaultResourceState<Country[]>([]),\n providers: createDefaultResourceState<Provider[], Provider | null>(\n [],\n null,\n ),\n tokens: createDefaultResourceState<\n TokensResponse | null,\n RampsToken | null\n >(null, null),\n paymentMethods: createDefaultResourceState<\n PaymentMethod[],\n PaymentMethod | null\n >([], null),\n quotes: createDefaultResourceState<QuotesResponse | null, Quote | null>(\n null,\n null,\n ),\n requests: {},\n };\n}\n\n/**\n * Resets region-dependent resources (userRegion, providers, tokens, paymentMethods, quotes).\n * Mutates state in place; use from within controller update() for atomic updates.\n *\n * @param state - The state object to mutate.\n * @param options - Options for the reset.\n * @param options.clearUserRegionData - When true, sets userRegion to null (e.g. for full cleanup).\n */\nfunction resetDependentResources(\n state: RampsControllerState,\n options?: { clearUserRegionData?: boolean },\n): void {\n if (options?.clearUserRegionData) {\n state.userRegion = null;\n }\n state.providers.selected = null;\n state.providers.data = [];\n state.providers.isLoading = false;\n state.providers.error = null;\n state.tokens.selected = null;\n state.tokens.data = null;\n state.tokens.isLoading = false;\n state.tokens.error = null;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n state.paymentMethods.isLoading = false;\n state.paymentMethods.error = null;\n state.quotes.data = null;\n state.quotes.selected = null;\n state.quotes.isLoading = false;\n state.quotes.error = null;\n}\n\n// === MESSENGER ===\n\n/**\n * Retrieves the state of the {@link RampsController}.\n */\nexport type RampsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Actions that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerActions = RampsControllerGetStateAction;\n\n/**\n * Actions from other messengers that {@link RampsController} calls.\n */\ntype AllowedActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction\n | RampsServiceGetProvidersAction\n | RampsServiceGetPaymentMethodsAction\n | RampsServiceGetQuotesAction;\n\n/**\n * Published when the state of {@link RampsController} changes.\n */\nexport type RampsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Events that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerEvents = RampsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link RampsController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link RampsController}.\n */\nexport type RampsControllerMessenger = Messenger<\n typeof controllerName,\n RampsControllerActions | AllowedActions,\n RampsControllerEvents | AllowedEvents\n>;\n\n/**\n * Configuration options for the RampsController.\n */\nexport type RampsControllerOptions = {\n /** The messenger suited for this controller. */\n messenger: RampsControllerMessenger;\n /** The desired state with which to initialize this controller. */\n state?: Partial<RampsControllerState>;\n /** Time to live for cached requests in milliseconds. Defaults to 15 minutes. */\n requestCacheTTL?: number;\n /** Maximum number of entries in the request cache. Defaults to 250. */\n requestCacheMaxSize?: number;\n};\n\n// === HELPER FUNCTIONS ===\n\n/**\n * Finds a country and state from a region code string.\n *\n * @param regionCode - The region code (e.g., \"us-ca\" or \"us\").\n * @param countries - Array of countries to search.\n * @returns UserRegion object with country and state, or null if not found.\n */\nfunction findRegionFromCode(\n regionCode: string,\n countries: Country[],\n): UserRegion | null {\n const normalizedCode = regionCode.toLowerCase().trim();\n const parts = normalizedCode.split('-');\n const countryCode = parts[0];\n const stateCode = parts[1];\n\n const country = countries.find((countryItem) => {\n if (countryItem.isoCode?.toLowerCase() === countryCode) {\n return true;\n }\n if (countryItem.id) {\n const id = countryItem.id.toLowerCase();\n if (id.startsWith('/regions/')) {\n const extractedCode = id.replace('/regions/', '').split('/')[0];\n return extractedCode === countryCode;\n }\n return id === countryCode || id.endsWith(`/${countryCode}`);\n }\n return false;\n });\n\n if (!country) {\n return null;\n }\n\n let state: State | null = null;\n if (stateCode && country.states) {\n state =\n country.states.find((stateItem) => {\n if (stateItem.stateId?.toLowerCase() === stateCode) {\n return true;\n }\n if (stateItem.id) {\n const stateId = stateItem.id.toLowerCase();\n if (\n stateId.includes(`-${stateCode}`) ||\n stateId.endsWith(`/${stateCode}`)\n ) {\n return true;\n }\n }\n return false;\n }) ?? null;\n }\n\n return {\n country,\n state,\n regionCode: normalizedCode,\n };\n}\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * Manages cryptocurrency on/off ramps functionality.\n */\nexport class RampsController extends BaseController<\n typeof controllerName,\n RampsControllerState,\n RampsControllerMessenger\n> {\n /**\n * Default TTL for cached requests.\n */\n readonly #requestCacheTTL: number;\n\n /**\n * Maximum number of entries in the request cache.\n */\n readonly #requestCacheMaxSize: number;\n\n /**\n * Map of pending requests for deduplication.\n * Key is the cache key, value is the pending request with abort controller.\n */\n readonly #pendingRequests: Map<string, PendingRequest> = new Map();\n\n /**\n * Count of in-flight requests per resource type.\n * Used so isLoading is only cleared when the last request for that resource finishes.\n */\n readonly #pendingResourceCount: Map<ResourceType, number> = new Map();\n\n /**\n * Interval ID for automatic quote polling.\n * Set when startQuotePolling() is called, cleared when stopQuotePolling() is called.\n */\n #quotePollingInterval: ReturnType<typeof setInterval> | null = null;\n\n /**\n * Options used for quote polling (walletAddress, amount, redirectUrl).\n * Stored so polling can be restarted when dependencies change.\n */\n #quotePollingOptions: {\n walletAddress: string;\n amount: number;\n redirectUrl?: string;\n } | null = null;\n\n /**\n * Clears the pending resource count map. Used only in tests to exercise the\n * defensive path when get() returns undefined in the finally block.\n *\n * @internal\n */\n clearPendingResourceCountForTest(): void {\n this.#pendingResourceCount.clear();\n }\n\n #clearPendingResourceCountForDependentResources(): void {\n const types: ResourceType[] = [\n 'providers',\n 'tokens',\n 'paymentMethods',\n 'quotes',\n ];\n for (const resourceType of types) {\n this.#pendingResourceCount.delete(resourceType);\n }\n }\n\n /**\n * Constructs a new {@link RampsController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to initialize this\n * controller. Missing properties will be filled in with defaults.\n * @param args.requestCacheTTL - Time to live for cached requests in milliseconds.\n * @param args.requestCacheMaxSize - Maximum number of entries in the request cache.\n */\n constructor({\n messenger,\n state = {},\n requestCacheTTL = DEFAULT_REQUEST_CACHE_TTL,\n requestCacheMaxSize = DEFAULT_REQUEST_CACHE_MAX_SIZE,\n }: RampsControllerOptions) {\n super({\n messenger,\n metadata: rampsControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultRampsControllerState(),\n ...state,\n // Always reset requests cache on initialization (non-persisted)\n requests: {},\n },\n });\n\n this.#requestCacheTTL = requestCacheTTL;\n this.#requestCacheMaxSize = requestCacheMaxSize;\n }\n\n /**\n * Executes a request with caching and deduplication.\n *\n * If a request with the same cache key is already in flight, returns the\n * existing promise. If valid cached data exists, returns it without making\n * a new request.\n *\n * @param cacheKey - Unique identifier for this request.\n * @param fetcher - Function that performs the actual fetch. Receives an AbortSignal.\n * @param options - Options for cache behavior.\n * @returns The result of the request.\n */\n async executeRequest<TResult>(\n cacheKey: string,\n fetcher: (signal: AbortSignal) => Promise<TResult>,\n options?: ExecuteRequestOptions,\n ): Promise<TResult> {\n const ttl = options?.ttl ?? this.#requestCacheTTL;\n\n // Check for existing pending request - join it instead of making a duplicate\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n return pending.promise as Promise<TResult>;\n }\n\n if (!options?.forceRefresh) {\n const cached = this.state.requests[cacheKey];\n if (cached && !isCacheExpired(cached, ttl)) {\n return cached.data as TResult;\n }\n }\n\n // Create abort controller for this request\n const abortController = new AbortController();\n const lastFetchedAt = Date.now();\n const { resourceType } = options ?? {};\n\n // Update state to loading\n this.#updateRequestState(cacheKey, createLoadingState());\n\n // Set resource-level loading state (only on cache miss). Ref-count so concurrent\n // requests for the same resource type (different cache keys) keep isLoading true.\n if (resourceType) {\n const count = this.#pendingResourceCount.get(resourceType) ?? 0;\n this.#pendingResourceCount.set(resourceType, count + 1);\n if (count === 0) {\n this.#setResourceLoading(resourceType, true);\n }\n }\n\n // Create the fetch promise\n const promise = (async (): Promise<TResult> => {\n try {\n const data = await fetcher(abortController.signal);\n\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw new Error('Request was aborted');\n }\n\n this.#updateRequestState(\n cacheKey,\n createSuccessState(data as Json, lastFetchedAt),\n );\n\n if (resourceType) {\n // We need the extra logic because there are two situations where we’re allowed to clear the error:\n // No callback → always clear\n // Callback present → clear only when isResultCurrent() returns true.\n const isCurrent =\n !options?.isResultCurrent || options.isResultCurrent();\n if (isCurrent) {\n this.#setResourceError(resourceType, null);\n }\n }\n\n return data;\n } catch (error) {\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw error;\n }\n\n const errorMessage = (error as Error)?.message ?? 'Unknown error';\n\n this.#updateRequestState(\n cacheKey,\n createErrorState(errorMessage, lastFetchedAt),\n );\n\n if (resourceType) {\n const isCurrent =\n !options?.isResultCurrent || options.isResultCurrent();\n if (isCurrent) {\n this.#setResourceError(resourceType, errorMessage);\n }\n }\n\n throw error;\n } finally {\n // Only delete if this is still our entry (not replaced by a new request)\n const currentPending = this.#pendingRequests.get(cacheKey);\n if (currentPending?.abortController === abortController) {\n this.#pendingRequests.delete(cacheKey);\n }\n\n // Clear resource-level loading state only when no requests for this resource remain\n if (resourceType) {\n const count = this.#pendingResourceCount.get(resourceType) ?? 0;\n const next = Math.max(0, count - 1);\n if (next === 0) {\n this.#pendingResourceCount.delete(resourceType);\n this.#setResourceLoading(resourceType, false);\n } else {\n this.#pendingResourceCount.set(resourceType, next);\n }\n }\n }\n })();\n\n // Store pending request for deduplication\n this.#pendingRequests.set(cacheKey, { promise, abortController });\n\n return promise;\n }\n\n /**\n * Aborts a pending request if one exists.\n *\n * @param cacheKey - The cache key of the request to abort.\n * @returns True if a request was aborted.\n */\n abortRequest(cacheKey: string): boolean {\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n pending.abortController.abort();\n this.#pendingRequests.delete(cacheKey);\n this.#removeRequestState(cacheKey);\n return true;\n }\n return false;\n }\n\n /**\n * Removes a request state from the cache.\n *\n * @param cacheKey - The cache key to remove.\n */\n #removeRequestState(cacheKey: string): void {\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n delete requests[cacheKey];\n });\n }\n\n #cleanupState(): void {\n this.stopQuotePolling();\n this.#clearPendingResourceCountForDependentResources();\n this.update((state) =>\n resetDependentResources(state as unknown as RampsControllerState, {\n clearUserRegionData: true,\n }),\n );\n }\n\n /**\n * Executes a promise without awaiting, swallowing errors.\n * Errors are stored in state via executeRequest.\n *\n * @param promise - The promise to execute.\n */\n #fireAndForget<Result>(promise: Promise<Result>): void {\n promise.catch((_error: unknown) => undefined);\n }\n\n /**\n * Restarts quote polling if it's currently active.\n * Used when dependencies change (token, provider, payment method).\n * Will only restart if all dependencies are still met (startQuotePolling validates this).\n */\n #restartPollingIfActive(): void {\n if (this.#quotePollingInterval !== null && this.#quotePollingOptions) {\n const options = this.#quotePollingOptions;\n this.stopQuotePolling();\n try {\n this.startQuotePolling(options);\n } catch {\n // Dependencies not met yet, polling will need to be manually restarted\n // when dependencies are available\n }\n }\n }\n\n /**\n * Updates a single field (isLoading or error) on a resource state.\n * All resources share the same ResourceState structure, so we use\n * dynamic property access to avoid duplicating switch statements.\n *\n * @param resourceType - The type of resource.\n * @param field - The field to update ('isLoading' or 'error').\n * @param value - The value to set.\n */\n #updateResourceField(\n resourceType: ResourceType,\n field: 'isLoading' | 'error',\n value: boolean | string | null,\n ): void {\n this.update((state) => {\n const resource = state[resourceType];\n if (resource) {\n (resource as Record<string, unknown>)[field] = value;\n }\n });\n }\n\n /**\n * Sets the loading state for a resource type.\n *\n * @param resourceType - The type of resource.\n * @param loading - Whether the resource is loading.\n */\n #setResourceLoading(resourceType: ResourceType, loading: boolean): void {\n this.#updateResourceField(resourceType, 'isLoading', loading);\n }\n\n /**\n * Sets the error state for a resource type.\n *\n * @param resourceType - The type of resource.\n * @param error - The error message, or null to clear.\n */\n #setResourceError(resourceType: ResourceType, error: string | null): void {\n this.#updateResourceField(resourceType, 'error', error);\n }\n\n /**\n * Gets the state of a specific cached request.\n *\n * @param cacheKey - The cache key to look up.\n * @returns The request state, or undefined if not cached.\n */\n getRequestState(cacheKey: string): RequestState | undefined {\n return this.state.requests[cacheKey];\n }\n\n /**\n * Updates the state for a specific request.\n *\n * @param cacheKey - The cache key.\n * @param requestState - The new state for the request.\n */\n #updateRequestState(cacheKey: string, requestState: RequestState): void {\n const maxSize = this.#requestCacheMaxSize;\n const ttl = this.#requestCacheTTL;\n\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n requests[cacheKey] = requestState;\n\n // Evict expired entries based on TTL\n // Only evict SUCCESS states that have exceeded their TTL\n const keys = Object.keys(requests);\n for (const key of keys) {\n const entry = requests[key];\n if (\n entry &&\n entry.status === RequestStatus.SUCCESS &&\n isCacheExpired(entry, ttl)\n ) {\n delete requests[key];\n }\n }\n\n // Evict oldest entries if cache still exceeds max size\n const remainingKeys = Object.keys(requests);\n if (remainingKeys.length > maxSize) {\n // Sort by timestamp (oldest first)\n const sortedKeys = remainingKeys.sort((a, b) => {\n const aTime = requests[a]?.timestamp ?? 0;\n const bTime = requests[b]?.timestamp ?? 0;\n return aTime - bTime;\n });\n\n // Remove oldest entries until we're under the limit\n const entriesToRemove = remainingKeys.length - maxSize;\n for (let i = 0; i < entriesToRemove; i++) {\n const keyToRemove = sortedKeys[i];\n if (keyToRemove) {\n delete requests[keyToRemove];\n }\n }\n }\n });\n }\n\n /**\n * Sets the user's region manually (without fetching geolocation).\n * This allows users to override the detected region.\n *\n * @param region - The region code to set (e.g., \"US-CA\").\n * @param options - Options for cache behavior.\n * @returns The user region object.\n */\n async setUserRegion(\n region: string,\n options?: ExecuteRequestOptions,\n ): Promise<UserRegion> {\n const normalizedRegion = region.toLowerCase().trim();\n\n try {\n const countriesData = this.state.countries.data;\n if (!countriesData || countriesData.length === 0) {\n this.#cleanupState();\n throw new Error(\n 'No countries found. Cannot set user region without valid country information.',\n );\n }\n\n const userRegion = findRegionFromCode(normalizedRegion, countriesData);\n\n if (!userRegion) {\n this.#cleanupState();\n throw new Error(\n `Region \"${normalizedRegion}\" not found in countries data. Cannot set user region without valid country information.`,\n );\n }\n\n const regionChanged =\n normalizedRegion !== this.state.userRegion?.regionCode;\n\n const needsRefetch =\n regionChanged ||\n !this.state.tokens.data ||\n this.state.providers.data.length === 0;\n\n if (regionChanged) {\n this.#clearPendingResourceCountForDependentResources();\n }\n if (regionChanged) {\n this.stopQuotePolling();\n }\n this.update((state) => {\n if (regionChanged) {\n resetDependentResources(state as unknown as RampsControllerState);\n }\n state.userRegion = userRegion;\n });\n\n if (needsRefetch) {\n const refetchPromises: Promise<unknown>[] = [];\n if (regionChanged || !this.state.tokens.data) {\n refetchPromises.push(\n this.getTokens(userRegion.regionCode, 'buy', options),\n );\n }\n if (regionChanged || this.state.providers.data.length === 0) {\n refetchPromises.push(\n this.getProviders(userRegion.regionCode, options),\n );\n }\n if (refetchPromises.length > 0) {\n this.#fireAndForget(Promise.all(refetchPromises));\n }\n }\n\n return userRegion;\n } catch (error) {\n this.#cleanupState();\n throw error;\n }\n }\n\n /**\n * Sets the user's selected provider by ID, or clears the selection.\n * Looks up the provider from the current providers in state and automatically\n * fetches payment methods for that provider.\n *\n * @param providerId - The provider ID (e.g., \"/providers/moonpay\"), or null to clear.\n * @throws If region is not set, providers are not loaded, or provider is not found.\n */\n setSelectedProvider(providerId: string | null): void {\n if (providerId === null) {\n this.stopQuotePolling();\n this.update((state) => {\n state.providers.selected = null;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n });\n return;\n }\n\n const regionCode = this.state.userRegion?.regionCode;\n if (!regionCode) {\n throw new Error(\n 'Region is required. Cannot set selected provider without valid region information.',\n );\n }\n\n const providers = this.state.providers.data;\n if (!providers || providers.length === 0) {\n throw new Error(\n 'Providers not loaded. Cannot set selected provider before providers are fetched.',\n );\n }\n\n const provider = providers.find((prov) => prov.id === providerId);\n if (!provider) {\n throw new Error(\n `Provider with ID \"${providerId}\" not found in available providers.`,\n );\n }\n\n this.update((state) => {\n state.providers.selected = provider;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n state.quotes.selected = null;\n });\n\n this.#fireAndForget(\n this.getPaymentMethods(regionCode, { provider: provider.id }).then(() => {\n // Restart quote polling after payment methods are fetched\n this.#restartPollingIfActive();\n return undefined;\n }),\n );\n }\n\n /**\n * Initializes the controller by fetching the user's region from geolocation.\n * This should be called once at app startup to set up the initial region.\n *\n * If a userRegion already exists (from persistence or manual selection),\n * this method will skip geolocation fetch and use the existing region.\n *\n * @param options - Options for cache behavior.\n * @returns Promise that resolves when initialization is complete.\n */\n async init(options?: ExecuteRequestOptions): Promise<void> {\n await this.getCountries(options);\n\n let regionCode = this.state.userRegion?.regionCode;\n regionCode ??= await this.messenger.call('RampsService:getGeolocation');\n\n if (!regionCode) {\n throw new Error(\n 'Failed to fetch geolocation. Cannot initialize controller without valid region information.',\n );\n }\n\n await this.setUserRegion(regionCode, options);\n }\n\n hydrateState(options?: ExecuteRequestOptions): void {\n const regionCode = this.state.userRegion?.regionCode;\n if (!regionCode) {\n throw new Error(\n 'Region code is required. Cannot hydrate state without valid region information.',\n );\n }\n\n this.#fireAndForget(this.getTokens(regionCode, 'buy', options));\n this.#fireAndForget(this.getProviders(regionCode, options));\n }\n\n /**\n * Fetches the list of supported countries.\n * The API returns countries with support information for both buy and sell actions.\n * The countries are saved in the controller state once fetched.\n *\n * @param options - Options for cache behavior.\n * @returns An array of countries.\n */\n async getCountries(options?: ExecuteRequestOptions): Promise<Country[]> {\n const cacheKey = createCacheKey('getCountries', []);\n\n const countries = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getCountries');\n },\n { ...options, resourceType: 'countries' },\n );\n\n this.update((state) => {\n state.countries.data = countries;\n });\n\n return countries;\n }\n\n /**\n * Fetches the list of available tokens for a given region and action.\n * The tokens are saved in the controller state once fetched.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\"). If not provided, uses the user's region from controller state.\n * @param action - The ramp action type ('buy' or 'sell').\n * @param options - Options for cache behavior and query filters.\n * @param options.provider - Provider ID(s) to filter by.\n * @returns The tokens response containing topTokens and allTokens.\n */\n async getTokens(\n region?: string,\n action: RampAction = 'buy',\n options?: ExecuteRequestOptions & {\n provider?: string | string[];\n },\n ): Promise<TokensResponse> {\n const regionToUse = region ?? this.state.userRegion?.regionCode;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getTokens', [\n normalizedRegion,\n action,\n options?.provider,\n ]);\n\n const tokens = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call(\n 'RampsService:getTokens',\n normalizedRegion,\n action,\n {\n provider: options?.provider,\n },\n );\n },\n {\n ...options,\n resourceType: 'tokens',\n isResultCurrent: () =>\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion,\n },\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.tokens.data = tokens;\n }\n });\n\n return tokens;\n }\n\n /**\n * Sets the user's selected token by asset ID.\n * Looks up the token from the current tokens in state and automatically\n * fetches payment methods for that token.\n *\n * @param assetId - The asset identifier in CAIP-19 format (e.g., \"eip155:1/erc20:0x...\"), or undefined to clear.\n * @throws If region is not set, tokens are not loaded, or token is not found.\n */\n setSelectedToken(assetId?: string): void {\n if (!assetId) {\n this.stopQuotePolling();\n this.update((state) => {\n state.tokens.selected = null;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n });\n return;\n }\n\n const regionCode = this.state.userRegion?.regionCode;\n if (!regionCode) {\n throw new Error(\n 'Region is required. Cannot set selected token without valid region information.',\n );\n }\n\n const tokens = this.state.tokens.data;\n if (!tokens) {\n throw new Error(\n 'Tokens not loaded. Cannot set selected token before tokens are fetched.',\n );\n }\n\n const token =\n tokens.allTokens.find((tok) => tok.assetId === assetId) ??\n tokens.topTokens.find((tok) => tok.assetId === assetId);\n\n if (!token) {\n throw new Error(\n `Token with asset ID \"${assetId}\" not found in available tokens.`,\n );\n }\n\n this.update((state) => {\n state.tokens.selected = token;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n state.quotes.selected = null;\n });\n\n this.#fireAndForget(\n this.getPaymentMethods(regionCode, { assetId: token.assetId }).then(\n () => {\n this.#restartPollingIfActive();\n return undefined;\n },\n ),\n );\n }\n\n /**\n * Fetches the list of providers for a given region.\n * The providers are saved in the controller state once fetched.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\"). If not provided, uses the user's region from controller state.\n * @param options - Options for cache behavior and query filters.\n * @param options.provider - Provider ID(s) to filter by.\n * @param options.crypto - Crypto currency ID(s) to filter by.\n * @param options.fiat - Fiat currency ID(s) to filter by.\n * @param options.payments - Payment method ID(s) to filter by.\n * @returns The providers response containing providers array.\n */\n async getProviders(\n region?: string,\n options?: ExecuteRequestOptions & {\n provider?: string | string[];\n crypto?: string | string[];\n fiat?: string | string[];\n payments?: string | string[];\n },\n ): Promise<{ providers: Provider[] }> {\n const regionToUse = region ?? this.state.userRegion?.regionCode;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getProviders', [\n normalizedRegion,\n options?.provider,\n options?.crypto,\n options?.fiat,\n options?.payments,\n ]);\n\n const { providers } = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call(\n 'RampsService:getProviders',\n normalizedRegion,\n {\n provider: options?.provider,\n crypto: options?.crypto,\n fiat: options?.fiat,\n payments: options?.payments,\n },\n );\n },\n {\n ...options,\n resourceType: 'providers',\n isResultCurrent: () =>\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion,\n },\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.providers.data = providers;\n }\n });\n\n return { providers };\n }\n\n /**\n * Fetches the list of payment methods for a given context.\n * The payment methods are saved in the controller state once fetched.\n *\n * @param region - User's region code (e.g. \"fr\", \"us-ny\").\n * @param options - Query parameters for filtering payment methods.\n * @param options.fiat - Fiat currency code (e.g., \"usd\"). If not provided, uses the user's region currency.\n * @param options.assetId - CAIP-19 cryptocurrency identifier.\n * @param options.provider - Provider ID path.\n * @returns The payment methods response containing payments array.\n */\n async getPaymentMethods(\n region?: string,\n options?: ExecuteRequestOptions & {\n fiat?: string;\n assetId?: string;\n provider?: string;\n },\n ): Promise<PaymentMethodsResponse> {\n const regionCode = region ?? this.state.userRegion?.regionCode ?? null;\n const fiatToUse =\n options?.fiat ?? this.state.userRegion?.country?.currency ?? null;\n const assetIdToUse =\n options?.assetId ?? this.state.tokens.selected?.assetId ?? '';\n const providerToUse =\n options?.provider ?? this.state.providers.selected?.id ?? '';\n\n if (!regionCode) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n if (!fiatToUse) {\n throw new Error(\n 'Fiat currency is required. Either provide a fiat parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionCode.toLowerCase().trim();\n const normalizedFiat = fiatToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getPaymentMethods', [\n normalizedRegion,\n normalizedFiat,\n assetIdToUse,\n providerToUse,\n ]);\n\n const response = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getPaymentMethods', {\n region: normalizedRegion,\n fiat: normalizedFiat,\n assetId: assetIdToUse,\n provider: providerToUse,\n });\n },\n {\n ...options,\n resourceType: 'paymentMethods',\n isResultCurrent: () => {\n const regionMatch =\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion;\n const tokenMatch =\n (this.state.tokens.selected?.assetId ?? '') === assetIdToUse;\n const providerMatch =\n (this.state.providers.selected?.id ?? '') === providerToUse;\n return regionMatch && tokenMatch && providerMatch;\n },\n },\n );\n\n this.update((state) => {\n const currentAssetId = state.tokens.selected?.assetId ?? '';\n const currentProviderId = state.providers.selected?.id ?? '';\n\n const tokenSelectionUnchanged = assetIdToUse === currentAssetId;\n const providerSelectionUnchanged = providerToUse === currentProviderId;\n\n // this is a race condition check to ensure that the selected token and provider in state are the same as the tokens we're requesting for\n // ex: if the user rapidly changes the token or provider, the in-flight payment methods might not be valid\n // so this check will ensure that the payment methods are still valid for the token and provider that were requested\n if (tokenSelectionUnchanged && providerSelectionUnchanged) {\n state.paymentMethods.data = response.payments;\n\n // this will auto-select the first payment method if the selected payment method is not in the new payment methods\n const currentSelectionStillValid = response.payments.some(\n (pm: PaymentMethod) => pm.id === state.paymentMethods.selected?.id,\n );\n if (!currentSelectionStillValid) {\n state.paymentMethods.selected = response.payments[0] ?? null;\n }\n }\n });\n\n return response;\n }\n\n /**\n * Sets the user's selected payment method by ID.\n * Looks up the payment method from the current payment methods in state.\n *\n * @param paymentMethodId - The payment method ID (e.g., \"/payments/debit-credit-card\"), or null to clear.\n * @throws If payment methods are not loaded or payment method is not found.\n */\n setSelectedPaymentMethod(paymentMethodId?: string): void {\n if (!paymentMethodId) {\n this.update((state) => {\n state.paymentMethods.selected = null;\n });\n return;\n }\n\n const paymentMethods = this.state.paymentMethods.data;\n if (!paymentMethods || paymentMethods.length === 0) {\n throw new Error(\n 'Payment methods not loaded. Cannot set selected payment method before payment methods are fetched.',\n );\n }\n\n const paymentMethod = paymentMethods.find(\n (pm) => pm.id === paymentMethodId,\n );\n if (!paymentMethod) {\n throw new Error(\n `Payment method with ID \"${paymentMethodId}\" not found in available payment methods.`,\n );\n }\n\n this.update((state) => {\n state.paymentMethods.selected = paymentMethod;\n });\n\n // Restart quote polling if active\n this.#restartPollingIfActive();\n }\n\n /**\n * Fetches quotes from all providers for a given set of parameters.\n * The quotes are saved in the controller state once fetched.\n *\n * @param options - The parameters for fetching quotes.\n * @param options.region - User's region code. If not provided, uses userRegion from state.\n * @param options.fiat - Fiat currency code. If not provided, uses userRegion currency.\n * @param options.assetId - CAIP-19 cryptocurrency identifier.\n * @param options.amount - The amount (in fiat for buy, crypto for sell).\n * @param options.walletAddress - The destination wallet address.\n * @param options.paymentMethods - Array of payment method IDs. If not provided, uses paymentMethods from state.\n * @param options.provider - Optional provider ID to filter quotes.\n * @param options.redirectUrl - Optional redirect URL after order completion.\n * @param options.action - The ramp action type. Defaults to 'buy'.\n * @param options.forceRefresh - Whether to bypass cache.\n * @param options.ttl - Custom TTL for this request.\n * @returns The quotes response containing success, sorted, error, and customActions.\n */\n async getQuotes(options: {\n region?: string;\n fiat?: string;\n assetId: string;\n amount: number;\n walletAddress: string;\n paymentMethods?: string[];\n provider?: string;\n redirectUrl?: string;\n action?: RampAction;\n forceRefresh?: boolean;\n ttl?: number;\n }): Promise<QuotesResponse> {\n const regionToUse = options.region ?? this.state.userRegion?.regionCode;\n const fiatToUse = options.fiat ?? this.state.userRegion?.country?.currency;\n const paymentMethodsToUse =\n options.paymentMethods ??\n this.state.paymentMethods.data.map((pm: PaymentMethod) => pm.id);\n const action = options.action ?? 'buy';\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n if (!fiatToUse) {\n throw new Error(\n 'Fiat currency is required. Either provide a fiat parameter or ensure userRegion is set in controller state.',\n );\n }\n\n if (!paymentMethodsToUse || paymentMethodsToUse.length === 0) {\n throw new Error(\n 'Payment methods are required. Either provide paymentMethods parameter or ensure paymentMethods are set in controller state.',\n );\n }\n\n if (options.amount <= 0 || !Number.isFinite(options.amount)) {\n throw new Error('Amount must be a positive finite number.');\n }\n\n if (!options.assetId || options.assetId.trim() === '') {\n throw new Error('assetId is required.');\n }\n\n if (!options.walletAddress || options.walletAddress.trim() === '') {\n throw new Error('walletAddress is required.');\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const normalizedFiat = fiatToUse.toLowerCase().trim();\n const normalizedAssetId = options.assetId.trim();\n const normalizedWalletAddress = options.walletAddress.trim();\n\n const cacheKey = createCacheKey('getQuotes', [\n normalizedRegion,\n normalizedFiat,\n normalizedAssetId,\n options.amount,\n normalizedWalletAddress,\n [...paymentMethodsToUse].sort().join(','),\n options.provider,\n options.redirectUrl,\n action,\n ]);\n\n const params: GetQuotesParams = {\n region: normalizedRegion,\n fiat: normalizedFiat,\n assetId: normalizedAssetId,\n amount: options.amount,\n walletAddress: normalizedWalletAddress,\n paymentMethods: paymentMethodsToUse,\n provider: options.provider,\n redirectUrl: options.redirectUrl,\n action,\n };\n\n const response = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getQuotes', params);\n },\n {\n forceRefresh: options.forceRefresh,\n ttl: options.ttl ?? DEFAULT_QUOTES_TTL,\n resourceType: 'quotes',\n isResultCurrent: () =>\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion,\n },\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.quotes.data = response;\n }\n });\n\n return response;\n }\n\n /**\n * Starts automatic quote polling with a 15-second refresh interval.\n * Fetches quotes immediately and then every 15 seconds.\n * If the response contains exactly one quote, it is auto-selected.\n * If multiple quotes are returned, the existing selection is preserved if still valid.\n *\n * @param options - Parameters for fetching quotes.\n * @param options.walletAddress - The destination wallet address.\n * @param options.amount - The amount (in fiat for buy, crypto for sell).\n * @param options.redirectUrl - Optional redirect URL after order completion.\n * @throws If required dependencies (region, token, provider, payment method) are not set.\n */\n startQuotePolling(options: {\n walletAddress: string;\n amount: number;\n redirectUrl?: string;\n }): void {\n // Validate required dependencies\n const regionCode = this.state.userRegion?.regionCode;\n const token = this.state.tokens.selected;\n const provider = this.state.providers.selected;\n const paymentMethod = this.state.paymentMethods.selected;\n\n if (!regionCode) {\n throw new Error(\n 'Region is required. Cannot start quote polling without valid region information.',\n );\n }\n\n if (!token) {\n throw new Error(\n 'Token is required. Cannot start quote polling without a selected token.',\n );\n }\n\n if (!provider) {\n throw new Error(\n 'Provider is required. Cannot start quote polling without a selected provider.',\n );\n }\n\n if (!paymentMethod) {\n return;\n }\n\n // Stop any existing polling first\n this.stopQuotePolling();\n\n // Store options for restarts (must be after stop to avoid being cleared)\n this.#quotePollingOptions = options;\n\n // Define the fetch function\n const fetchQuotes = (): void => {\n this.#fireAndForget(\n this.getQuotes({\n assetId: token.assetId,\n amount: options.amount,\n walletAddress: options.walletAddress,\n redirectUrl: options.redirectUrl,\n paymentMethods: [paymentMethod.id],\n provider: provider.id,\n forceRefresh: true,\n }).then((response) => {\n // Auto-select logic: only when exactly one quote is returned\n this.update((state) => {\n if (response.success.length === 1) {\n state.quotes.selected = response.success[0];\n } else {\n // Keep existing selection if still valid, but update with fresh data\n const currentSelection = state.quotes.selected;\n if (currentSelection) {\n const freshQuote = response.success.find(\n (quote) =>\n quote.provider === currentSelection.provider &&\n quote.quote.paymentMethod ===\n currentSelection.quote.paymentMethod,\n );\n // Update with fresh quote data, or clear if no longer valid\n state.quotes.selected = freshQuote ?? null;\n }\n }\n });\n return undefined;\n }),\n );\n };\n\n // Fetch immediately\n fetchQuotes();\n\n // Set up 15-second polling\n this.#quotePollingInterval = setInterval(fetchQuotes, 15000);\n }\n\n /**\n * Stops automatic quote polling.\n * Does not clear quotes data or selection, only stops the interval.\n */\n stopQuotePolling(): void {\n if (this.#quotePollingInterval !== null) {\n clearInterval(this.#quotePollingInterval);\n this.#quotePollingInterval = null;\n }\n this.#quotePollingOptions = null;\n }\n\n /**\n * Manually sets the selected quote.\n *\n * @param quote - The quote to select, or null to clear the selection.\n */\n setSelectedQuote(quote: Quote | null): void {\n this.update((state) => {\n state.quotes.selected = quote;\n });\n }\n\n /**\n * Cleans up controller resources.\n * Stops any active quote polling to prevent memory leaks.\n * Should be called when the controller is no longer needed.\n */\n override destroy(): void {\n this.stopQuotePolling();\n super.destroy();\n }\n\n /**\n * Extracts the widget URL from a quote for redirect providers.\n * Returns the widget URL if available, or null if the quote doesn't have one.\n *\n * @param quote - The quote to extract the widget URL from.\n * @returns The widget URL string, or null if not available.\n */\n getWidgetUrl(quote: Quote): string | null {\n return quote.quote?.widgetUrl ?? null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RampsController.cjs","sourceRoot":"","sources":["../src/RampsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\n\nimport type {\n Country,\n TokensResponse,\n Provider,\n State,\n RampAction,\n PaymentMethod,\n PaymentMethodsResponse,\n QuotesResponse,\n Quote,\n RampsToken,\n RampsServiceActions,\n} from './RampsService';\nimport type {\n RampsServiceGetGeolocationAction,\n RampsServiceGetCountriesAction,\n RampsServiceGetTokensAction,\n RampsServiceGetProvidersAction,\n RampsServiceGetPaymentMethodsAction,\n RampsServiceGetQuotesAction,\n RampsServiceGetBuyWidgetUrlAction,\n} from './RampsService-method-action-types';\nimport type {\n RequestCache as RequestCacheType,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n ResourceType,\n} from './RequestCache';\nimport {\n DEFAULT_REQUEST_CACHE_TTL,\n DEFAULT_REQUEST_CACHE_MAX_SIZE,\n createCacheKey,\n isCacheExpired,\n createLoadingState,\n createSuccessState,\n createErrorState,\n RequestStatus,\n} from './RequestCache';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link RampsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'RampsController';\n\n/**\n * RampsService action types that RampsController calls via the messenger.\n * Any host (e.g. mobile) that creates a RampsController messenger must delegate\n * these actions from the root messenger so the controller can function.\n */\nexport const RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS: readonly RampsServiceActions['type'][] =\n [\n 'RampsService:getGeolocation',\n 'RampsService:getCountries',\n 'RampsService:getTokens',\n 'RampsService:getProviders',\n 'RampsService:getPaymentMethods',\n 'RampsService:getQuotes',\n 'RampsService:getBuyWidgetUrl',\n ];\n\n/**\n * Default TTL for quotes requests (15 seconds).\n * Quotes are time-sensitive and should have a shorter cache duration.\n */\nconst DEFAULT_QUOTES_TTL = 15000;\n\n// === STATE ===\n\n/**\n * Represents the user's selected region with full country and state objects.\n */\nexport type UserRegion = {\n /**\n * The country object for the selected region.\n */\n country: Country;\n /**\n * The state object if a state was selected, null if only country was selected.\n */\n state: State | null;\n /**\n * The region code string (e.g., \"us-ut\" or \"fr\") used for API calls.\n */\n regionCode: string;\n};\n\n/**\n * Generic type for resource state that bundles data with loading/error states.\n *\n * @template TData - The type of the resource data\n * @template TSelected - The type of the selected item (defaults to null for resources without selection)\n */\nexport type ResourceState<TData, TSelected = null> = {\n /**\n * The resource data.\n */\n data: TData;\n /**\n * The currently selected item, or null if none selected.\n */\n selected: TSelected;\n /**\n * Whether the resource is currently being fetched.\n */\n isLoading: boolean;\n /**\n * Error message if the fetch failed, or null.\n */\n error: string | null;\n};\n\n/**\n * Describes the shape of the state object for {@link RampsController}.\n */\nexport type RampsControllerState = {\n /**\n * The user's region (full country and state objects).\n * Initially set via geolocation fetch, but can be manually changed by the user.\n */\n userRegion: UserRegion | null;\n /**\n * Countries resource state with data, loading, and error.\n * Data contains the list of countries available for ramp actions.\n */\n countries: ResourceState<Country[]>;\n /**\n * Providers resource state with data, selected, loading, and error.\n * Data contains the list of providers available for the current region.\n */\n providers: ResourceState<Provider[], Provider | null>;\n /**\n * Tokens resource state with data, selected, loading, and error.\n * Data contains topTokens and allTokens arrays.\n */\n tokens: ResourceState<TokensResponse | null, RampsToken | null>;\n /**\n * Payment methods resource state with data, selected, loading, and error.\n * Data contains payment methods filtered by region, fiat, asset, and provider.\n */\n paymentMethods: ResourceState<PaymentMethod[], PaymentMethod | null>;\n /**\n * Quotes resource state with data, selected, loading, and error.\n * Data contains quotes from multiple providers for the given parameters.\n * Selected contains the currently selected quote for the user.\n */\n quotes: ResourceState<QuotesResponse | null, Quote | null>;\n /**\n * Cache of request states, keyed by cache key.\n * This stores loading, success, and error states for API requests.\n */\n requests: RequestCacheType;\n};\n\n/**\n * The metadata for each property in {@link RampsControllerState}.\n */\nconst rampsControllerMetadata = {\n userRegion: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n countries: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n providers: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n tokens: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n paymentMethods: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n quotes: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: false,\n usedInUi: true,\n },\n requests: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: false,\n usedInUi: true,\n },\n} satisfies StateMetadata<RampsControllerState>;\n\n/**\n * Creates a default resource state object.\n *\n * @template TData - The type of the resource data.\n * @template TSelected - The type of the selected item.\n * @param data - The initial data value.\n * @param selected - The initial selected value.\n * @returns A ResourceState object with default loading and error values.\n */\nfunction createDefaultResourceState<TData, TSelected = null>(\n data: TData,\n selected: TSelected = null as TSelected,\n): ResourceState<TData, TSelected> {\n return {\n data,\n selected,\n isLoading: false,\n error: null,\n };\n}\n\n/**\n * Constructs the default {@link RampsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link RampsController} state.\n */\nexport function getDefaultRampsControllerState(): RampsControllerState {\n return {\n userRegion: null,\n countries: createDefaultResourceState<Country[]>([]),\n providers: createDefaultResourceState<Provider[], Provider | null>(\n [],\n null,\n ),\n tokens: createDefaultResourceState<\n TokensResponse | null,\n RampsToken | null\n >(null, null),\n paymentMethods: createDefaultResourceState<\n PaymentMethod[],\n PaymentMethod | null\n >([], null),\n quotes: createDefaultResourceState<QuotesResponse | null, Quote | null>(\n null,\n null,\n ),\n requests: {},\n };\n}\n\n/**\n * Resets region-dependent resources (userRegion, providers, tokens, paymentMethods, quotes).\n * Mutates state in place; use from within controller update() for atomic updates.\n *\n * @param state - The state object to mutate.\n * @param options - Options for the reset.\n * @param options.clearUserRegionData - When true, sets userRegion to null (e.g. for full cleanup).\n */\nfunction resetDependentResources(\n state: RampsControllerState,\n options?: { clearUserRegionData?: boolean },\n): void {\n if (options?.clearUserRegionData) {\n state.userRegion = null;\n }\n state.providers.selected = null;\n state.providers.data = [];\n state.providers.isLoading = false;\n state.providers.error = null;\n state.tokens.selected = null;\n state.tokens.data = null;\n state.tokens.isLoading = false;\n state.tokens.error = null;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n state.paymentMethods.isLoading = false;\n state.paymentMethods.error = null;\n state.quotes.data = null;\n state.quotes.selected = null;\n state.quotes.isLoading = false;\n state.quotes.error = null;\n}\n\n// === MESSENGER ===\n\n/**\n * Retrieves the state of the {@link RampsController}.\n */\nexport type RampsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Actions that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerActions = RampsControllerGetStateAction;\n\n/**\n * Actions from other messengers that {@link RampsController} calls.\n */\ntype AllowedActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction\n | RampsServiceGetProvidersAction\n | RampsServiceGetPaymentMethodsAction\n | RampsServiceGetQuotesAction\n | RampsServiceGetBuyWidgetUrlAction;\n\n/**\n * Published when the state of {@link RampsController} changes.\n */\nexport type RampsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Events that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerEvents = RampsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link RampsController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link RampsController}.\n */\nexport type RampsControllerMessenger = Messenger<\n typeof controllerName,\n RampsControllerActions | AllowedActions,\n RampsControllerEvents | AllowedEvents\n>;\n\n/**\n * Configuration options for the RampsController.\n */\nexport type RampsControllerOptions = {\n /** The messenger suited for this controller. */\n messenger: RampsControllerMessenger;\n /** The desired state with which to initialize this controller. */\n state?: Partial<RampsControllerState>;\n /** Time to live for cached requests in milliseconds. Defaults to 15 minutes. */\n requestCacheTTL?: number;\n /** Maximum number of entries in the request cache. Defaults to 250. */\n requestCacheMaxSize?: number;\n};\n\n// === HELPER FUNCTIONS ===\n\n/**\n * Finds a country and state from a region code string.\n *\n * @param regionCode - The region code (e.g., \"us-ca\" or \"us\").\n * @param countries - Array of countries to search.\n * @returns UserRegion object with country and state, or null if not found.\n */\nfunction findRegionFromCode(\n regionCode: string,\n countries: Country[],\n): UserRegion | null {\n const normalizedCode = regionCode.toLowerCase().trim();\n const parts = normalizedCode.split('-');\n const countryCode = parts[0];\n const stateCode = parts[1];\n\n const country = countries.find((countryItem) => {\n if (countryItem.isoCode?.toLowerCase() === countryCode) {\n return true;\n }\n if (countryItem.id) {\n const id = countryItem.id.toLowerCase();\n if (id.startsWith('/regions/')) {\n const extractedCode = id.replace('/regions/', '').split('/')[0];\n return extractedCode === countryCode;\n }\n return id === countryCode || id.endsWith(`/${countryCode}`);\n }\n return false;\n });\n\n if (!country) {\n return null;\n }\n\n let state: State | null = null;\n if (stateCode && country.states) {\n state =\n country.states.find((stateItem) => {\n if (stateItem.stateId?.toLowerCase() === stateCode) {\n return true;\n }\n if (stateItem.id) {\n const stateId = stateItem.id.toLowerCase();\n if (\n stateId.includes(`-${stateCode}`) ||\n stateId.endsWith(`/${stateCode}`)\n ) {\n return true;\n }\n }\n return false;\n }) ?? null;\n }\n\n return {\n country,\n state,\n regionCode: normalizedCode,\n };\n}\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * Manages cryptocurrency on/off ramps functionality.\n */\nexport class RampsController extends BaseController<\n typeof controllerName,\n RampsControllerState,\n RampsControllerMessenger\n> {\n /**\n * Default TTL for cached requests.\n */\n readonly #requestCacheTTL: number;\n\n /**\n * Maximum number of entries in the request cache.\n */\n readonly #requestCacheMaxSize: number;\n\n /**\n * Map of pending requests for deduplication.\n * Key is the cache key, value is the pending request with abort controller.\n */\n readonly #pendingRequests: Map<string, PendingRequest> = new Map();\n\n /**\n * Count of in-flight requests per resource type.\n * Used so isLoading is only cleared when the last request for that resource finishes.\n */\n readonly #pendingResourceCount: Map<ResourceType, number> = new Map();\n\n /**\n * Interval ID for automatic quote polling.\n * Set when startQuotePolling() is called, cleared when stopQuotePolling() is called.\n */\n #quotePollingInterval: ReturnType<typeof setInterval> | null = null;\n\n /**\n * Options used for quote polling (walletAddress, amount, redirectUrl).\n * Stored so polling can be restarted when dependencies change.\n */\n #quotePollingOptions: {\n walletAddress: string;\n amount: number;\n redirectUrl?: string;\n } | null = null;\n\n /**\n * Clears the pending resource count map. Used only in tests to exercise the\n * defensive path when get() returns undefined in the finally block.\n *\n * @internal\n */\n clearPendingResourceCountForTest(): void {\n this.#pendingResourceCount.clear();\n }\n\n #clearPendingResourceCountForDependentResources(): void {\n const types: ResourceType[] = [\n 'providers',\n 'tokens',\n 'paymentMethods',\n 'quotes',\n ];\n for (const resourceType of types) {\n this.#pendingResourceCount.delete(resourceType);\n }\n }\n\n /**\n * Constructs a new {@link RampsController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to initialize this\n * controller. Missing properties will be filled in with defaults.\n * @param args.requestCacheTTL - Time to live for cached requests in milliseconds.\n * @param args.requestCacheMaxSize - Maximum number of entries in the request cache.\n */\n constructor({\n messenger,\n state = {},\n requestCacheTTL = DEFAULT_REQUEST_CACHE_TTL,\n requestCacheMaxSize = DEFAULT_REQUEST_CACHE_MAX_SIZE,\n }: RampsControllerOptions) {\n super({\n messenger,\n metadata: rampsControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultRampsControllerState(),\n ...state,\n // Always reset requests cache on initialization (non-persisted)\n requests: {},\n },\n });\n\n this.#requestCacheTTL = requestCacheTTL;\n this.#requestCacheMaxSize = requestCacheMaxSize;\n }\n\n /**\n * Executes a request with caching and deduplication.\n *\n * If a request with the same cache key is already in flight, returns the\n * existing promise. If valid cached data exists, returns it without making\n * a new request.\n *\n * @param cacheKey - Unique identifier for this request.\n * @param fetcher - Function that performs the actual fetch. Receives an AbortSignal.\n * @param options - Options for cache behavior.\n * @returns The result of the request.\n */\n async executeRequest<TResult>(\n cacheKey: string,\n fetcher: (signal: AbortSignal) => Promise<TResult>,\n options?: ExecuteRequestOptions,\n ): Promise<TResult> {\n const ttl = options?.ttl ?? this.#requestCacheTTL;\n\n // Check for existing pending request - join it instead of making a duplicate\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n return pending.promise as Promise<TResult>;\n }\n\n if (!options?.forceRefresh) {\n const cached = this.state.requests[cacheKey];\n if (cached && !isCacheExpired(cached, ttl)) {\n return cached.data as TResult;\n }\n }\n\n // Create abort controller for this request\n const abortController = new AbortController();\n const lastFetchedAt = Date.now();\n const { resourceType } = options ?? {};\n\n // Update state to loading\n this.#updateRequestState(cacheKey, createLoadingState());\n\n // Set resource-level loading state (only on cache miss). Ref-count so concurrent\n // requests for the same resource type (different cache keys) keep isLoading true.\n if (resourceType) {\n const count = this.#pendingResourceCount.get(resourceType) ?? 0;\n this.#pendingResourceCount.set(resourceType, count + 1);\n if (count === 0) {\n this.#setResourceLoading(resourceType, true);\n }\n }\n\n // Create the fetch promise\n const promise = (async (): Promise<TResult> => {\n try {\n const data = await fetcher(abortController.signal);\n\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw new Error('Request was aborted');\n }\n\n this.#updateRequestState(\n cacheKey,\n createSuccessState(data as Json, lastFetchedAt),\n );\n\n if (resourceType) {\n // We need the extra logic because there are two situations where we’re allowed to clear the error:\n // No callback → always clear\n // Callback present → clear only when isResultCurrent() returns true.\n const isCurrent =\n !options?.isResultCurrent || options.isResultCurrent();\n if (isCurrent) {\n this.#setResourceError(resourceType, null);\n }\n }\n\n return data;\n } catch (error) {\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw error;\n }\n\n const errorMessage = (error as Error)?.message ?? 'Unknown error';\n\n this.#updateRequestState(\n cacheKey,\n createErrorState(errorMessage, lastFetchedAt),\n );\n\n if (resourceType) {\n const isCurrent =\n !options?.isResultCurrent || options.isResultCurrent();\n if (isCurrent) {\n this.#setResourceError(resourceType, errorMessage);\n }\n }\n\n throw error;\n } finally {\n // Only delete if this is still our entry (not replaced by a new request)\n const currentPending = this.#pendingRequests.get(cacheKey);\n if (currentPending?.abortController === abortController) {\n this.#pendingRequests.delete(cacheKey);\n }\n\n // Clear resource-level loading state only when no requests for this resource remain\n if (resourceType) {\n const count = this.#pendingResourceCount.get(resourceType) ?? 0;\n const next = Math.max(0, count - 1);\n if (next === 0) {\n this.#pendingResourceCount.delete(resourceType);\n this.#setResourceLoading(resourceType, false);\n } else {\n this.#pendingResourceCount.set(resourceType, next);\n }\n }\n }\n })();\n\n // Store pending request for deduplication\n this.#pendingRequests.set(cacheKey, { promise, abortController });\n\n return promise;\n }\n\n /**\n * Aborts a pending request if one exists.\n *\n * @param cacheKey - The cache key of the request to abort.\n * @returns True if a request was aborted.\n */\n abortRequest(cacheKey: string): boolean {\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n pending.abortController.abort();\n this.#pendingRequests.delete(cacheKey);\n this.#removeRequestState(cacheKey);\n return true;\n }\n return false;\n }\n\n /**\n * Removes a request state from the cache.\n *\n * @param cacheKey - The cache key to remove.\n */\n #removeRequestState(cacheKey: string): void {\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n delete requests[cacheKey];\n });\n }\n\n #cleanupState(): void {\n this.stopQuotePolling();\n this.#clearPendingResourceCountForDependentResources();\n this.update((state) =>\n resetDependentResources(state as unknown as RampsControllerState, {\n clearUserRegionData: true,\n }),\n );\n }\n\n /**\n * Executes a promise without awaiting, swallowing errors.\n * Errors are stored in state via executeRequest.\n *\n * @param promise - The promise to execute.\n */\n #fireAndForget<Result>(promise: Promise<Result>): void {\n promise.catch((_error: unknown) => undefined);\n }\n\n /**\n * Restarts quote polling if it's currently active.\n * Used when dependencies change (token, provider, payment method).\n * Will only restart if all dependencies are still met (startQuotePolling validates this).\n */\n #restartPollingIfActive(): void {\n if (this.#quotePollingInterval !== null && this.#quotePollingOptions) {\n const options = this.#quotePollingOptions;\n this.stopQuotePolling();\n try {\n this.startQuotePolling(options);\n } catch {\n // Dependencies not met yet, polling will need to be manually restarted\n // when dependencies are available\n }\n }\n }\n\n /**\n * Updates a single field (isLoading or error) on a resource state.\n * All resources share the same ResourceState structure, so we use\n * dynamic property access to avoid duplicating switch statements.\n *\n * @param resourceType - The type of resource.\n * @param field - The field to update ('isLoading' or 'error').\n * @param value - The value to set.\n */\n #updateResourceField(\n resourceType: ResourceType,\n field: 'isLoading' | 'error',\n value: boolean | string | null,\n ): void {\n this.update((state) => {\n const resource = state[resourceType];\n if (resource) {\n (resource as Record<string, unknown>)[field] = value;\n }\n });\n }\n\n /**\n * Sets the loading state for a resource type.\n *\n * @param resourceType - The type of resource.\n * @param loading - Whether the resource is loading.\n */\n #setResourceLoading(resourceType: ResourceType, loading: boolean): void {\n this.#updateResourceField(resourceType, 'isLoading', loading);\n }\n\n /**\n * Sets the error state for a resource type.\n *\n * @param resourceType - The type of resource.\n * @param error - The error message, or null to clear.\n */\n #setResourceError(resourceType: ResourceType, error: string | null): void {\n this.#updateResourceField(resourceType, 'error', error);\n }\n\n /**\n * Gets the state of a specific cached request.\n *\n * @param cacheKey - The cache key to look up.\n * @returns The request state, or undefined if not cached.\n */\n getRequestState(cacheKey: string): RequestState | undefined {\n return this.state.requests[cacheKey];\n }\n\n /**\n * Updates the state for a specific request.\n *\n * @param cacheKey - The cache key.\n * @param requestState - The new state for the request.\n */\n #updateRequestState(cacheKey: string, requestState: RequestState): void {\n const maxSize = this.#requestCacheMaxSize;\n const ttl = this.#requestCacheTTL;\n\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n requests[cacheKey] = requestState;\n\n // Evict expired entries based on TTL\n // Only evict SUCCESS states that have exceeded their TTL\n const keys = Object.keys(requests);\n for (const key of keys) {\n const entry = requests[key];\n if (\n entry?.status === RequestStatus.SUCCESS &&\n isCacheExpired(entry, ttl)\n ) {\n delete requests[key];\n }\n }\n\n // Evict oldest entries if cache still exceeds max size\n const remainingKeys = Object.keys(requests);\n if (remainingKeys.length > maxSize) {\n // Sort by timestamp (oldest first)\n const sortedKeys = remainingKeys.sort((a, b) => {\n const aTime = requests[a]?.timestamp ?? 0;\n const bTime = requests[b]?.timestamp ?? 0;\n return aTime - bTime;\n });\n\n // Remove oldest entries until we're under the limit\n const entriesToRemove = remainingKeys.length - maxSize;\n for (let i = 0; i < entriesToRemove; i++) {\n const keyToRemove = sortedKeys[i];\n if (keyToRemove) {\n delete requests[keyToRemove];\n }\n }\n }\n });\n }\n\n /**\n * Sets the user's region manually (without fetching geolocation).\n * This allows users to override the detected region.\n *\n * @param region - The region code to set (e.g., \"US-CA\").\n * @param options - Options for cache behavior.\n * @returns The user region object.\n */\n async setUserRegion(\n region: string,\n options?: ExecuteRequestOptions,\n ): Promise<UserRegion> {\n const normalizedRegion = region.toLowerCase().trim();\n\n try {\n const countriesData = this.state.countries.data;\n if (!countriesData || countriesData.length === 0) {\n this.#cleanupState();\n throw new Error(\n 'No countries found. Cannot set user region without valid country information.',\n );\n }\n\n const userRegion = findRegionFromCode(normalizedRegion, countriesData);\n\n if (!userRegion) {\n this.#cleanupState();\n throw new Error(\n `Region \"${normalizedRegion}\" not found in countries data. Cannot set user region without valid country information.`,\n );\n }\n\n const regionChanged =\n normalizedRegion !== this.state.userRegion?.regionCode;\n\n const needsRefetch =\n regionChanged ||\n !this.state.tokens.data ||\n this.state.providers.data.length === 0;\n\n if (regionChanged) {\n this.#clearPendingResourceCountForDependentResources();\n }\n if (regionChanged) {\n this.stopQuotePolling();\n }\n this.update((state) => {\n if (regionChanged) {\n resetDependentResources(state as unknown as RampsControllerState);\n }\n state.userRegion = userRegion;\n });\n\n if (needsRefetch) {\n const refetchPromises: Promise<unknown>[] = [];\n if (regionChanged || !this.state.tokens.data) {\n refetchPromises.push(\n this.getTokens(userRegion.regionCode, 'buy', options),\n );\n }\n if (regionChanged || this.state.providers.data.length === 0) {\n refetchPromises.push(\n this.getProviders(userRegion.regionCode, options),\n );\n }\n if (refetchPromises.length > 0) {\n this.#fireAndForget(Promise.all(refetchPromises));\n }\n }\n\n return userRegion;\n } catch (error) {\n this.#cleanupState();\n throw error;\n }\n }\n\n /**\n * Sets the user's selected provider by ID, or clears the selection.\n * Looks up the provider from the current providers in state and automatically\n * fetches payment methods for that provider.\n *\n * @param providerId - The provider ID (e.g., \"/providers/moonpay\"), or null to clear.\n * @throws If region is not set, providers are not loaded, or provider is not found.\n */\n setSelectedProvider(providerId: string | null): void {\n if (providerId === null) {\n this.stopQuotePolling();\n this.update((state) => {\n state.providers.selected = null;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n });\n return;\n }\n\n const regionCode = this.state.userRegion?.regionCode;\n if (!regionCode) {\n throw new Error(\n 'Region is required. Cannot set selected provider without valid region information.',\n );\n }\n\n const providers = this.state.providers.data;\n if (!providers || providers.length === 0) {\n throw new Error(\n 'Providers not loaded. Cannot set selected provider before providers are fetched.',\n );\n }\n\n const provider = providers.find((prov) => prov.id === providerId);\n if (!provider) {\n throw new Error(\n `Provider with ID \"${providerId}\" not found in available providers.`,\n );\n }\n\n this.update((state) => {\n state.providers.selected = provider;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n state.quotes.selected = null;\n });\n\n this.#fireAndForget(\n this.getPaymentMethods(regionCode, { provider: provider.id }).then(() => {\n // Restart quote polling after payment methods are fetched\n this.#restartPollingIfActive();\n return undefined;\n }),\n );\n }\n\n /**\n * Initializes the controller by fetching the user's region from geolocation.\n * This should be called once at app startup to set up the initial region.\n *\n * If a userRegion already exists (from persistence or manual selection),\n * this method will skip geolocation fetch and use the existing region.\n *\n * @param options - Options for cache behavior.\n * @returns Promise that resolves when initialization is complete.\n */\n async init(options?: ExecuteRequestOptions): Promise<void> {\n await this.getCountries(options);\n\n let regionCode = this.state.userRegion?.regionCode;\n regionCode ??= await this.messenger.call('RampsService:getGeolocation');\n\n if (!regionCode) {\n throw new Error(\n 'Failed to fetch geolocation. Cannot initialize controller without valid region information.',\n );\n }\n\n await this.setUserRegion(regionCode, options);\n }\n\n hydrateState(options?: ExecuteRequestOptions): void {\n const regionCode = this.state.userRegion?.regionCode;\n if (!regionCode) {\n throw new Error(\n 'Region code is required. Cannot hydrate state without valid region information.',\n );\n }\n\n this.#fireAndForget(this.getTokens(regionCode, 'buy', options));\n this.#fireAndForget(this.getProviders(regionCode, options));\n }\n\n /**\n * Fetches the list of supported countries.\n * The API returns countries with support information for both buy and sell actions.\n * The countries are saved in the controller state once fetched.\n *\n * @param options - Options for cache behavior.\n * @returns An array of countries.\n */\n async getCountries(options?: ExecuteRequestOptions): Promise<Country[]> {\n const cacheKey = createCacheKey('getCountries', []);\n\n const countries = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getCountries');\n },\n { ...options, resourceType: 'countries' },\n );\n\n this.update((state) => {\n state.countries.data = countries;\n });\n\n return countries;\n }\n\n /**\n * Fetches the list of available tokens for a given region and action.\n * The tokens are saved in the controller state once fetched.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\"). If not provided, uses the user's region from controller state.\n * @param action - The ramp action type ('buy' or 'sell').\n * @param options - Options for cache behavior and query filters.\n * @param options.provider - Provider ID(s) to filter by.\n * @returns The tokens response containing topTokens and allTokens.\n */\n async getTokens(\n region?: string,\n action: RampAction = 'buy',\n options?: ExecuteRequestOptions & {\n provider?: string | string[];\n },\n ): Promise<TokensResponse> {\n const regionToUse = region ?? this.state.userRegion?.regionCode;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getTokens', [\n normalizedRegion,\n action,\n options?.provider,\n ]);\n\n const tokens = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call(\n 'RampsService:getTokens',\n normalizedRegion,\n action,\n {\n provider: options?.provider,\n },\n );\n },\n {\n ...options,\n resourceType: 'tokens',\n isResultCurrent: () =>\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion,\n },\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.tokens.data = tokens;\n }\n });\n\n return tokens;\n }\n\n /**\n * Sets the user's selected token by asset ID.\n * Looks up the token from the current tokens in state and automatically\n * fetches payment methods for that token.\n *\n * @param assetId - The asset identifier in CAIP-19 format (e.g., \"eip155:1/erc20:0x...\"), or undefined to clear.\n * @throws If region is not set, tokens are not loaded, or token is not found.\n */\n setSelectedToken(assetId?: string): void {\n if (!assetId) {\n this.stopQuotePolling();\n this.update((state) => {\n state.tokens.selected = null;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n });\n return;\n }\n\n const regionCode = this.state.userRegion?.regionCode;\n if (!regionCode) {\n throw new Error(\n 'Region is required. Cannot set selected token without valid region information.',\n );\n }\n\n const tokens = this.state.tokens.data;\n if (!tokens) {\n throw new Error(\n 'Tokens not loaded. Cannot set selected token before tokens are fetched.',\n );\n }\n\n const token =\n tokens.allTokens.find((tok) => tok.assetId === assetId) ??\n tokens.topTokens.find((tok) => tok.assetId === assetId);\n\n if (!token) {\n throw new Error(\n `Token with asset ID \"${assetId}\" not found in available tokens.`,\n );\n }\n\n this.update((state) => {\n state.tokens.selected = token;\n state.paymentMethods.data = [];\n state.paymentMethods.selected = null;\n state.quotes.selected = null;\n });\n\n this.#fireAndForget(\n this.getPaymentMethods(regionCode, { assetId: token.assetId }).then(\n () => {\n this.#restartPollingIfActive();\n return undefined;\n },\n ),\n );\n }\n\n /**\n * Fetches the list of providers for a given region.\n * The providers are saved in the controller state once fetched.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\"). If not provided, uses the user's region from controller state.\n * @param options - Options for cache behavior and query filters.\n * @param options.provider - Provider ID(s) to filter by.\n * @param options.crypto - Crypto currency ID(s) to filter by.\n * @param options.fiat - Fiat currency ID(s) to filter by.\n * @param options.payments - Payment method ID(s) to filter by.\n * @returns The providers response containing providers array.\n */\n async getProviders(\n region?: string,\n options?: ExecuteRequestOptions & {\n provider?: string | string[];\n crypto?: string | string[];\n fiat?: string | string[];\n payments?: string | string[];\n },\n ): Promise<{ providers: Provider[] }> {\n const regionToUse = region ?? this.state.userRegion?.regionCode;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getProviders', [\n normalizedRegion,\n options?.provider,\n options?.crypto,\n options?.fiat,\n options?.payments,\n ]);\n\n const { providers } = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call(\n 'RampsService:getProviders',\n normalizedRegion,\n {\n provider: options?.provider,\n crypto: options?.crypto,\n fiat: options?.fiat,\n payments: options?.payments,\n },\n );\n },\n {\n ...options,\n resourceType: 'providers',\n isResultCurrent: () =>\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion,\n },\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.providers.data = providers;\n }\n });\n\n return { providers };\n }\n\n /**\n * Fetches the list of payment methods for a given context.\n * The payment methods are saved in the controller state once fetched.\n *\n * @param region - User's region code (e.g. \"fr\", \"us-ny\").\n * @param options - Query parameters for filtering payment methods.\n * @param options.fiat - Fiat currency code (e.g., \"usd\"). If not provided, uses the user's region currency.\n * @param options.assetId - CAIP-19 cryptocurrency identifier.\n * @param options.provider - Provider ID path.\n * @returns The payment methods response containing payments array.\n */\n async getPaymentMethods(\n region?: string,\n options?: ExecuteRequestOptions & {\n fiat?: string;\n assetId?: string;\n provider?: string;\n },\n ): Promise<PaymentMethodsResponse> {\n const regionCode = region ?? this.state.userRegion?.regionCode ?? null;\n const fiatToUse =\n options?.fiat ?? this.state.userRegion?.country?.currency ?? null;\n const assetIdToUse =\n options?.assetId ?? this.state.tokens.selected?.assetId ?? '';\n const providerToUse =\n options?.provider ?? this.state.providers.selected?.id ?? '';\n\n if (!regionCode) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n if (!fiatToUse) {\n throw new Error(\n 'Fiat currency is required. Either provide a fiat parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionCode.toLowerCase().trim();\n const normalizedFiat = fiatToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getPaymentMethods', [\n normalizedRegion,\n normalizedFiat,\n assetIdToUse,\n providerToUse,\n ]);\n\n const response = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getPaymentMethods', {\n region: normalizedRegion,\n fiat: normalizedFiat,\n assetId: assetIdToUse,\n provider: providerToUse,\n });\n },\n {\n ...options,\n resourceType: 'paymentMethods',\n isResultCurrent: () => {\n const regionMatch =\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion;\n const tokenMatch =\n (this.state.tokens.selected?.assetId ?? '') === assetIdToUse;\n const providerMatch =\n (this.state.providers.selected?.id ?? '') === providerToUse;\n return regionMatch && tokenMatch && providerMatch;\n },\n },\n );\n\n this.update((state) => {\n const currentAssetId = state.tokens.selected?.assetId ?? '';\n const currentProviderId = state.providers.selected?.id ?? '';\n\n const tokenSelectionUnchanged = assetIdToUse === currentAssetId;\n const providerSelectionUnchanged = providerToUse === currentProviderId;\n\n // this is a race condition check to ensure that the selected token and provider in state are the same as the tokens we're requesting for\n // ex: if the user rapidly changes the token or provider, the in-flight payment methods might not be valid\n // so this check will ensure that the payment methods are still valid for the token and provider that were requested\n if (tokenSelectionUnchanged && providerSelectionUnchanged) {\n state.paymentMethods.data = response.payments;\n\n // this will auto-select the first payment method if the selected payment method is not in the new payment methods\n const currentSelectionStillValid = response.payments.some(\n (pm: PaymentMethod) => pm.id === state.paymentMethods.selected?.id,\n );\n if (!currentSelectionStillValid) {\n state.paymentMethods.selected = response.payments[0] ?? null;\n }\n }\n });\n\n return response;\n }\n\n /**\n * Sets the user's selected payment method by ID.\n * Looks up the payment method from the current payment methods in state.\n *\n * @param paymentMethodId - The payment method ID (e.g., \"/payments/debit-credit-card\"), or null to clear.\n * @throws If payment methods are not loaded or payment method is not found.\n */\n setSelectedPaymentMethod(paymentMethodId?: string): void {\n if (!paymentMethodId) {\n this.update((state) => {\n state.paymentMethods.selected = null;\n });\n return;\n }\n\n const paymentMethods = this.state.paymentMethods.data;\n if (!paymentMethods || paymentMethods.length === 0) {\n throw new Error(\n 'Payment methods not loaded. Cannot set selected payment method before payment methods are fetched.',\n );\n }\n\n const paymentMethod = paymentMethods.find(\n (pm) => pm.id === paymentMethodId,\n );\n if (!paymentMethod) {\n throw new Error(\n `Payment method with ID \"${paymentMethodId}\" not found in available payment methods.`,\n );\n }\n\n this.update((state) => {\n state.paymentMethods.selected = paymentMethod;\n });\n\n // Restart quote polling if active\n this.#restartPollingIfActive();\n }\n\n /**\n * Fetches quotes from all providers for a given set of parameters.\n * The quotes are saved in the controller state once fetched.\n *\n * @param options - The parameters for fetching quotes.\n * @param options.region - User's region code. If not provided, uses userRegion from state.\n * @param options.fiat - Fiat currency code. If not provided, uses userRegion currency.\n * @param options.assetId - CAIP-19 cryptocurrency identifier.\n * @param options.amount - The amount (in fiat for buy, crypto for sell).\n * @param options.walletAddress - The destination wallet address.\n * @param options.paymentMethods - Array of payment method IDs. If not provided, uses paymentMethods from state.\n * @param options.providers - Optional provider IDs to filter quotes.\n * @param options.redirectUrl - Optional redirect URL after order completion.\n * @param options.action - The ramp action type. Defaults to 'buy'.\n * @param options.forceRefresh - Whether to bypass cache.\n * @param options.ttl - Custom TTL for this request.\n * @returns The quotes response containing success, sorted, error, and customActions.\n */\n async getQuotes(options: {\n region?: string;\n fiat?: string;\n assetId?: string;\n amount: number;\n walletAddress: string;\n paymentMethods?: string[];\n providers?: string[];\n redirectUrl?: string;\n action?: RampAction;\n forceRefresh?: boolean;\n ttl?: number;\n }): Promise<QuotesResponse> {\n const regionToUse = options.region ?? this.state.userRegion?.regionCode;\n const fiatToUse = options.fiat ?? this.state.userRegion?.country?.currency;\n const paymentMethodsToUse =\n options.paymentMethods ??\n this.state.paymentMethods.data.map((pm: PaymentMethod) => pm.id);\n const providersToUse =\n options.providers ??\n this.state.providers.data.map((provider: Provider) => provider.id);\n const action = options.action ?? 'buy';\n const assetIdToUse = options.assetId ?? this.state.tokens.selected?.assetId;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n if (!fiatToUse) {\n throw new Error(\n 'Fiat currency is required. Either provide a fiat parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedAssetIdForValidation = (assetIdToUse ?? '').trim();\n if (normalizedAssetIdForValidation === '') {\n throw new Error('assetId is required.');\n }\n\n if (\n !paymentMethodsToUse ||\n paymentMethodsToUse.length === 0 ||\n paymentMethodsToUse.some((pm) => pm.trim() === '')\n ) {\n throw new Error(\n 'Payment methods are required. Either provide paymentMethods parameter or ensure paymentMethods are set in controller state.',\n );\n }\n\n if (options.amount <= 0 || !Number.isFinite(options.amount)) {\n throw new Error('Amount must be a positive finite number.');\n }\n\n if (!options.walletAddress || options.walletAddress.trim() === '') {\n throw new Error('walletAddress is required.');\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const normalizedFiat = fiatToUse.toLowerCase().trim();\n const normalizedAssetId = normalizedAssetIdForValidation;\n const normalizedWalletAddress = options.walletAddress.trim();\n\n const cacheKey = createCacheKey('getQuotes', [\n normalizedRegion,\n normalizedFiat,\n normalizedAssetId,\n options.amount,\n normalizedWalletAddress,\n [...paymentMethodsToUse].sort().join(','),\n [...providersToUse].sort().join(','),\n options.redirectUrl,\n action,\n ]);\n\n const params = {\n region: normalizedRegion,\n fiat: normalizedFiat,\n assetId: normalizedAssetId,\n amount: options.amount,\n walletAddress: normalizedWalletAddress,\n paymentMethods: paymentMethodsToUse,\n providers: providersToUse,\n redirectUrl: options.redirectUrl,\n action,\n };\n\n const response = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getQuotes', params);\n },\n {\n forceRefresh: options.forceRefresh,\n ttl: options.ttl ?? DEFAULT_QUOTES_TTL,\n resourceType: 'quotes',\n isResultCurrent: () =>\n this.state.userRegion?.regionCode === undefined ||\n this.state.userRegion?.regionCode === normalizedRegion,\n },\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.quotes.data = response;\n }\n });\n\n return response;\n }\n\n /**\n * Starts automatic quote polling with a 15-second refresh interval.\n * Fetches quotes immediately and then every 15 seconds.\n * If the response contains exactly one quote, it is auto-selected.\n * If multiple quotes are returned, the existing selection is preserved if still valid.\n *\n * @param options - Parameters for fetching quotes.\n * @param options.walletAddress - The destination wallet address.\n * @param options.amount - The amount (in fiat for buy, crypto for sell).\n * @param options.redirectUrl - Optional redirect URL after order completion.\n * @throws If required dependencies (region, token, provider, payment method) are not set.\n */\n startQuotePolling(options: {\n walletAddress: string;\n amount: number;\n redirectUrl?: string;\n }): void {\n // Validate required dependencies\n const regionCode = this.state.userRegion?.regionCode;\n const token = this.state.tokens.selected;\n const provider = this.state.providers.selected;\n const paymentMethod = this.state.paymentMethods.selected;\n\n if (!regionCode) {\n throw new Error(\n 'Region is required. Cannot start quote polling without valid region information.',\n );\n }\n\n if (!token) {\n throw new Error(\n 'Token is required. Cannot start quote polling without a selected token.',\n );\n }\n\n if (!provider) {\n throw new Error(\n 'Provider is required. Cannot start quote polling without a selected provider.',\n );\n }\n\n if (!paymentMethod) {\n return;\n }\n\n // Stop any existing polling first\n this.stopQuotePolling();\n\n // Store options for restarts (must be after stop to avoid being cleared)\n this.#quotePollingOptions = options;\n\n // Define the fetch function\n const fetchQuotes = (): void => {\n this.#fireAndForget(\n this.getQuotes({\n assetId: token.assetId,\n amount: options.amount,\n walletAddress: options.walletAddress,\n redirectUrl: options.redirectUrl,\n paymentMethods: [paymentMethod.id],\n providers: [provider.id],\n forceRefresh: true,\n }).then((response) => {\n // Auto-select logic: only when exactly one quote is returned\n this.update((state) => {\n if (response.success.length === 1) {\n state.quotes.selected = response.success[0];\n } else {\n // Keep existing selection if still valid, but update with fresh data\n const currentSelection = state.quotes.selected;\n if (currentSelection) {\n const freshQuote = response.success.find(\n (quote) =>\n quote.provider === currentSelection.provider &&\n quote.quote.paymentMethod ===\n currentSelection.quote.paymentMethod,\n );\n // Update with fresh quote data, or clear if no longer valid\n state.quotes.selected = freshQuote ?? null;\n }\n }\n });\n return undefined;\n }),\n );\n };\n\n // Fetch immediately\n fetchQuotes();\n\n // Set up 15-second polling\n this.#quotePollingInterval = setInterval(fetchQuotes, 15000);\n }\n\n /**\n * Stops automatic quote polling.\n * Does not clear quotes data or selection, only stops the interval.\n */\n stopQuotePolling(): void {\n if (this.#quotePollingInterval !== null) {\n clearInterval(this.#quotePollingInterval);\n this.#quotePollingInterval = null;\n }\n this.#quotePollingOptions = null;\n }\n\n /**\n * Manually sets the selected quote.\n *\n * @param quote - The quote to select, or null to clear the selection.\n */\n setSelectedQuote(quote: Quote | null): void {\n this.update((state) => {\n state.quotes.selected = quote;\n });\n }\n\n /**\n * Cleans up controller resources.\n * Stops any active quote polling to prevent memory leaks.\n * Should be called when the controller is no longer needed.\n */\n override destroy(): void {\n this.stopQuotePolling();\n super.destroy();\n }\n\n /**\n * Fetches the widget URL from a quote for redirect providers.\n * Makes a request to the buyURL endpoint via the RampsService to get the\n * actual provider widget URL, using the injected fetch and retry policy.\n *\n * @param quote - The quote to fetch the widget URL from.\n * @returns Promise resolving to the widget URL string, or null if not available.\n */\n async getWidgetUrl(quote: Quote): Promise<string | null> {\n const buyUrl = quote.quote?.buyURL;\n if (!buyUrl) {\n return null;\n }\n\n try {\n const buyWidget = await this.messenger.call(\n 'RampsService:getBuyWidgetUrl',\n buyUrl,\n );\n return buyWidget.url ?? null;\n } catch (error) {\n console.error('Error fetching widget URL:', error);\n return null;\n }\n }\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@meta
|
|
|
2
2
|
import { BaseController } from "@metamask/base-controller";
|
|
3
3
|
import type { Messenger } from "@metamask/messenger";
|
|
4
4
|
import type { Country, TokensResponse, Provider, State, RampAction, PaymentMethod, PaymentMethodsResponse, QuotesResponse, Quote, RampsToken, RampsServiceActions } from "./RampsService.cjs";
|
|
5
|
-
import type { RampsServiceGetGeolocationAction, RampsServiceGetCountriesAction, RampsServiceGetTokensAction, RampsServiceGetProvidersAction, RampsServiceGetPaymentMethodsAction, RampsServiceGetQuotesAction } from "./RampsService-method-action-types.cjs";
|
|
5
|
+
import type { RampsServiceGetGeolocationAction, RampsServiceGetCountriesAction, RampsServiceGetTokensAction, RampsServiceGetProvidersAction, RampsServiceGetPaymentMethodsAction, RampsServiceGetQuotesAction, RampsServiceGetBuyWidgetUrlAction } from "./RampsService-method-action-types.cjs";
|
|
6
6
|
import type { RequestCache as RequestCacheType, RequestState, ExecuteRequestOptions } from "./RequestCache.cjs";
|
|
7
7
|
/**
|
|
8
8
|
* The name of the {@link RampsController}, used to namespace the
|
|
@@ -118,7 +118,7 @@ export type RampsControllerActions = RampsControllerGetStateAction;
|
|
|
118
118
|
/**
|
|
119
119
|
* Actions from other messengers that {@link RampsController} calls.
|
|
120
120
|
*/
|
|
121
|
-
type AllowedActions = RampsServiceGetGeolocationAction | RampsServiceGetCountriesAction | RampsServiceGetTokensAction | RampsServiceGetProvidersAction | RampsServiceGetPaymentMethodsAction | RampsServiceGetQuotesAction;
|
|
121
|
+
type AllowedActions = RampsServiceGetGeolocationAction | RampsServiceGetCountriesAction | RampsServiceGetTokensAction | RampsServiceGetProvidersAction | RampsServiceGetPaymentMethodsAction | RampsServiceGetQuotesAction | RampsServiceGetBuyWidgetUrlAction;
|
|
122
122
|
/**
|
|
123
123
|
* Published when the state of {@link RampsController} changes.
|
|
124
124
|
*/
|
|
@@ -315,7 +315,7 @@ export declare class RampsController extends BaseController<typeof controllerNam
|
|
|
315
315
|
* @param options.amount - The amount (in fiat for buy, crypto for sell).
|
|
316
316
|
* @param options.walletAddress - The destination wallet address.
|
|
317
317
|
* @param options.paymentMethods - Array of payment method IDs. If not provided, uses paymentMethods from state.
|
|
318
|
-
* @param options.
|
|
318
|
+
* @param options.providers - Optional provider IDs to filter quotes.
|
|
319
319
|
* @param options.redirectUrl - Optional redirect URL after order completion.
|
|
320
320
|
* @param options.action - The ramp action type. Defaults to 'buy'.
|
|
321
321
|
* @param options.forceRefresh - Whether to bypass cache.
|
|
@@ -325,11 +325,11 @@ export declare class RampsController extends BaseController<typeof controllerNam
|
|
|
325
325
|
getQuotes(options: {
|
|
326
326
|
region?: string;
|
|
327
327
|
fiat?: string;
|
|
328
|
-
assetId
|
|
328
|
+
assetId?: string;
|
|
329
329
|
amount: number;
|
|
330
330
|
walletAddress: string;
|
|
331
331
|
paymentMethods?: string[];
|
|
332
|
-
|
|
332
|
+
providers?: string[];
|
|
333
333
|
redirectUrl?: string;
|
|
334
334
|
action?: RampAction;
|
|
335
335
|
forceRefresh?: boolean;
|
|
@@ -370,13 +370,14 @@ export declare class RampsController extends BaseController<typeof controllerNam
|
|
|
370
370
|
*/
|
|
371
371
|
destroy(): void;
|
|
372
372
|
/**
|
|
373
|
-
*
|
|
374
|
-
*
|
|
373
|
+
* Fetches the widget URL from a quote for redirect providers.
|
|
374
|
+
* Makes a request to the buyURL endpoint via the RampsService to get the
|
|
375
|
+
* actual provider widget URL, using the injected fetch and retry policy.
|
|
375
376
|
*
|
|
376
|
-
* @param quote - The quote to
|
|
377
|
-
* @returns
|
|
377
|
+
* @param quote - The quote to fetch the widget URL from.
|
|
378
|
+
* @returns Promise resolving to the widget URL string, or null if not available.
|
|
378
379
|
*/
|
|
379
|
-
getWidgetUrl(quote: Quote): string | null
|
|
380
|
+
getWidgetUrl(quote: Quote): Promise<string | null>;
|
|
380
381
|
}
|
|
381
382
|
export {};
|
|
382
383
|
//# sourceMappingURL=RampsController.d.cts.map
|