@metamask-previews/assets-controllers 109.1.0-preview-a4db237 → 109.1.0-preview-8cbb66949
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 +0 -3
- package/dist/CurrencyRateController.cjs +3 -33
- package/dist/CurrencyRateController.cjs.map +1 -1
- package/dist/CurrencyRateController.d.cts +1 -8
- package/dist/CurrencyRateController.d.cts.map +1 -1
- package/dist/CurrencyRateController.d.mts +1 -8
- package/dist/CurrencyRateController.d.mts.map +1 -1
- package/dist/CurrencyRateController.mjs +3 -33
- package/dist/CurrencyRateController.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,9 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
-
- Add `isDeprecated` option to `CurrencyRateController` constructor ([#9182](https://github.com/MetaMask/core/pull/9182))
|
|
13
|
-
- When `isDeprecated()` returns `true`, no API requests are sent and `currencyRates` is reset to `{}` at construction and at every entry point (`setCurrentCurrency`, `updateExchangeRate`, and `_executePoll`), so no stale rates remain in state.
|
|
14
|
-
- The function is re-evaluated on each entry point so it can be toggled at runtime without reconstructing the controller.
|
|
15
12
|
- Add `isDeprecated` option to `MultichainAssetsRatesController` constructor ([#9044](https://github.com/MetaMask/core/pull/9044))
|
|
16
13
|
- When `isDeprecated()` returns `true`, no Snap requests are sent and `conversionRates` and `historicalPrices` are reset to `{}` at construction and at every entry point (`updateAssetsRates`, `fetchHistoricalPricesForAsset`, `_executePoll`, `CurrencyRateController:stateChange`, and `MultichainAssetsController:accountAssetListUpdated`), so no stale rates remain in state.
|
|
17
14
|
- The function is re-evaluated on each entry point so it can be toggled at runtime without reconstructing the controller.
|
|
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _CurrencyRateController_instances, _CurrencyRateController_mutex, _CurrencyRateController_includeUsdRate, _CurrencyRateController_useExternalServices, _CurrencyRateController_tokenPricesService,
|
|
13
|
+
var _CurrencyRateController_instances, _CurrencyRateController_mutex, _CurrencyRateController_includeUsdRate, _CurrencyRateController_useExternalServices, _CurrencyRateController_tokenPricesService, _CurrencyRateController_fetchRatesFromPriceApi, _CurrencyRateController_fetchRatesFromTokenPricesService, _CurrencyRateController_createNullRatesForCurrencies, _CurrencyRateController_fetchExchangeRatesWithFallback;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.CurrencyRateController = void 0;
|
|
16
16
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
@@ -62,14 +62,8 @@ class CurrencyRateController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
62
62
|
* @param options.state - Initial state to set on this controller.
|
|
63
63
|
* @param options.useExternalServices - Feature Switch for using external services (default: true)
|
|
64
64
|
* @param options.tokenPricesService - An object in charge of retrieving token prices
|
|
65
|
-
* @param options.isDeprecated - Optional function that returns true to completely
|
|
66
|
-
* disable this controller (no requests, no state updates). When it returns
|
|
67
|
-
* `true`, `currencyRates` is reset to `{}` at construction and at every entry point,
|
|
68
|
-
* so no stale rates remain in state. The function is evaluated dynamically
|
|
69
|
-
* on each entry point so it can be toggled at runtime. Intended for use when
|
|
70
|
-
* a higher-level controller (e.g. AssetsController) supersedes this one.
|
|
71
65
|
*/
|
|
72
|
-
constructor({ includeUsdRate = false, interval = 180000, useExternalServices = () => true,
|
|
66
|
+
constructor({ includeUsdRate = false, interval = 180000, useExternalServices = () => true, messenger, state, tokenPricesService, }) {
|
|
73
67
|
super({
|
|
74
68
|
name,
|
|
75
69
|
metadata,
|
|
@@ -81,15 +75,10 @@ class CurrencyRateController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
81
75
|
_CurrencyRateController_includeUsdRate.set(this, void 0);
|
|
82
76
|
_CurrencyRateController_useExternalServices.set(this, void 0);
|
|
83
77
|
_CurrencyRateController_tokenPricesService.set(this, void 0);
|
|
84
|
-
_CurrencyRateController_isDeprecated.set(this, void 0);
|
|
85
78
|
__classPrivateFieldSet(this, _CurrencyRateController_includeUsdRate, includeUsdRate, "f");
|
|
86
79
|
__classPrivateFieldSet(this, _CurrencyRateController_useExternalServices, useExternalServices, "f");
|
|
87
80
|
this.setIntervalLength(interval);
|
|
88
81
|
__classPrivateFieldSet(this, _CurrencyRateController_tokenPricesService, tokenPricesService, "f");
|
|
89
|
-
__classPrivateFieldSet(this, _CurrencyRateController_isDeprecated, isDeprecated, "f");
|
|
90
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
91
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
92
|
-
}
|
|
93
82
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
94
83
|
}
|
|
95
84
|
/**
|
|
@@ -98,10 +87,6 @@ class CurrencyRateController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
98
87
|
* @param currentCurrency - ISO 4217 currency code.
|
|
99
88
|
*/
|
|
100
89
|
async setCurrentCurrency(currentCurrency) {
|
|
101
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
102
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
90
|
const releaseLock = await __classPrivateFieldGet(this, _CurrencyRateController_mutex, "f").acquire();
|
|
106
91
|
const nativeCurrencies = Object.keys(this.state.currencyRates);
|
|
107
92
|
try {
|
|
@@ -125,10 +110,6 @@ class CurrencyRateController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
125
110
|
* @param nativeCurrencies - The native currency symbols to fetch exchange rates for.
|
|
126
111
|
*/
|
|
127
112
|
async updateExchangeRate(nativeCurrencies) {
|
|
128
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
129
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
113
|
if (!__classPrivateFieldGet(this, _CurrencyRateController_useExternalServices, "f").call(this)) {
|
|
133
114
|
return;
|
|
134
115
|
}
|
|
@@ -178,22 +159,11 @@ class CurrencyRateController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
178
159
|
* @param input.nativeCurrencies - The native currency symbols to poll prices for.
|
|
179
160
|
*/
|
|
180
161
|
async _executePoll({ nativeCurrencies, }) {
|
|
181
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
182
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
162
|
await this.updateExchangeRate(nativeCurrencies);
|
|
186
163
|
}
|
|
187
164
|
}
|
|
188
165
|
exports.CurrencyRateController = CurrencyRateController;
|
|
189
|
-
_CurrencyRateController_mutex = new WeakMap(), _CurrencyRateController_includeUsdRate = new WeakMap(), _CurrencyRateController_useExternalServices = new WeakMap(), _CurrencyRateController_tokenPricesService = new WeakMap(),
|
|
190
|
-
if (Object.keys(this.state.currencyRates).length === 0) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
this.update((state) => {
|
|
194
|
-
state.currencyRates = {};
|
|
195
|
-
});
|
|
196
|
-
}, _CurrencyRateController_fetchRatesFromPriceApi =
|
|
166
|
+
_CurrencyRateController_mutex = new WeakMap(), _CurrencyRateController_includeUsdRate = new WeakMap(), _CurrencyRateController_useExternalServices = new WeakMap(), _CurrencyRateController_tokenPricesService = new WeakMap(), _CurrencyRateController_instances = new WeakSet(), _CurrencyRateController_fetchRatesFromPriceApi =
|
|
197
167
|
/**
|
|
198
168
|
* Attempts to fetch exchange rates from the primary Price API.
|
|
199
169
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyRateController.cjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { CurrencyRateControllerMethodActions } from './CurrencyRateController-method-action-types';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'setCurrentCurrency',\n 'updateExchangeRate',\n] as const;\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type CurrencyRateControllerGetStateAction = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions =\n | CurrencyRateControllerGetStateAction\n | CurrencyRateControllerMethodActions;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\nconst boundedPrecisionNumber = (value: number, precision = 9): number =>\n Number(value.toFixed(precision));\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\n/** Result from attempting to fetch rates from an API */\ntype FetchRatesResult = {\n /** Successfully fetched rates */\n rates: CurrencyRateState['currencyRates'];\n /** Currencies that failed and need fallback or null state */\n failedCurrencies: Record<string, string>;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n readonly #mutex = new Mutex();\n\n readonly #includeUsdRate: boolean;\n\n readonly #useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n readonly #isDeprecated: () => boolean;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n * @param options.isDeprecated - Optional function that returns true to completely\n * disable this controller (no requests, no state updates). When it returns\n * `true`, `currencyRates` is reset to `{}` at construction and at every entry point,\n * so no stale rates remain in state. The function is evaluated dynamically\n * on each entry point so it can be toggled at runtime. Intended for use when\n * a higher-level controller (e.g. AssetsController) supersedes this one.\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n isDeprecated = (): boolean => false,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n isDeprecated?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.#includeUsdRate = includeUsdRate;\n this.#useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n this.#isDeprecated = isDeprecated;\n\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n }\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Clears all persisted `currencyRates` so that no stale rates remain in state.\n *\n * Called from every entry point when `isDeprecated()` is true so that a\n * runtime toggle propagates to state immediately, even if the controller was\n * originally constructed while it was enabled. The update is skipped when\n * `currencyRates` is already empty to avoid emitting redundant state changes.\n */\n #enforceDisabledState(): void {\n if (Object.keys(this.state.currencyRates).length === 0) {\n return;\n }\n this.update((state) => {\n state.currencyRates = {};\n });\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string): Promise<void> {\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n return;\n }\n\n const releaseLock = await this.#mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.updateExchangeRate(nativeCurrencies);\n }\n\n /**\n * Attempts to fetch exchange rates from the primary Price API.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromPriceApi(\n nativeCurrenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n const rates: CurrencyRateState['currencyRates'] = {};\n let failedCurrencies: Record<string, string> = {};\n\n try {\n const response = await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.#includeUsdRate,\n cryptocurrencies: [...new Set(Object.values(nativeCurrenciesToFetch))],\n });\n\n Object.entries(nativeCurrenciesToFetch).forEach(\n ([nativeCurrency, fetchedCurrency]) => {\n const rate = response[fetchedCurrency.toLowerCase()];\n\n if (rate?.value) {\n rates[nativeCurrency] = {\n conversionDate: Date.now() / 1000,\n conversionRate: boundedPrecisionNumber(1 / rate.value),\n usdConversionRate: rate?.usd\n ? boundedPrecisionNumber(1 / rate.usd)\n : null,\n };\n } else {\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n },\n );\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n failedCurrencies = { ...nativeCurrenciesToFetch };\n }\n\n return { rates, failedCurrencies };\n }\n\n /**\n * Fetches exchange rates from the token prices service as a fallback.\n * This method is designed to never throw - all errors are handled internally\n * and result in currencies being marked as failed.\n *\n * @param currenciesToFetch - Map of native currencies that need fallback fetching.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromTokenPricesService(\n currenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n try {\n const rates: CurrencyRateState['currencyRates'] = {};\n const failedCurrencies: Record<string, string> = {};\n\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Build a map of nativeCurrency -> chainId for currencies to fetch\n const currencyToChainIds = Object.entries(currenciesToFetch).reduce<\n Record<string, { fetchedCurrency: string; chainId: Hex }>\n >((acc, [nativeCurrency, fetchedCurrency]) => {\n const matchingEntry = (\n Object.entries(networkConfigurations) as [Hex, NetworkConfiguration][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = { fetchedCurrency, chainId: matchingEntry[0] };\n } else {\n // No matching network configuration - mark as failed\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n return acc;\n }, {});\n\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n assets: [{ chainId, tokenAddress: nativeTokenAddress }],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices.find(\n (item) =>\n item.tokenAddress.toLowerCase() ===\n nativeTokenAddress.toLowerCase(),\n );\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price\n ? boundedPrecisionNumber(tokenPrice.price)\n : null,\n usdConversionRate: null,\n };\n }),\n );\n\n ratesResults.forEach((result, index) => {\n const [nativeCurrency, { fetchedCurrency, chainId }] =\n currencyToChainIdsEntries[index];\n\n if (result.status === 'fulfilled' && result.value.conversionRate) {\n rates[nativeCurrency] = {\n conversionDate: result.value.conversionDate,\n conversionRate: result.value.conversionRate,\n usdConversionRate: result.value.usdConversionRate,\n };\n } else {\n if (result.status === 'rejected') {\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n }\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n });\n\n return { rates, failedCurrencies };\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return all currencies as failed\n return { rates: {}, failedCurrencies: { ...currenciesToFetch } };\n }\n }\n\n /**\n * Creates null rate entries for currencies that couldn't be fetched.\n *\n * @param currencies - Array of currency symbols to create null entries for.\n * @returns Null rate entries for all provided currencies.\n */\n #createNullRatesForCurrencies(\n currencies: string[],\n ): CurrencyRateState['currencyRates'] {\n return currencies.reduce<CurrencyRateState['currencyRates']>(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {},\n );\n }\n\n /**\n * Fetches exchange rates with fallback logic.\n * First tries the Price API, then falls back to token prices service for any failed currencies.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @returns Exchange rates for all requested currencies.\n */\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n // Step 1: Try the Price API exchange rates first\n const {\n rates: ratesPriceApi,\n failedCurrencies: failedCurrenciesFromPriceApi,\n } = await this.#fetchRatesFromPriceApi(\n nativeCurrenciesToFetch,\n currentCurrency,\n );\n\n // Step 2: If all currencies succeeded, return early\n if (Object.keys(failedCurrenciesFromPriceApi).length === 0) {\n return ratesPriceApi;\n }\n\n // Step 3: Fallback using token prices service for failed currencies\n const {\n rates: ratesFromFallback,\n failedCurrencies: failedCurrenciesFromFallback,\n } = await this.#fetchRatesFromTokenPricesService(\n failedCurrenciesFromPriceApi,\n currentCurrency,\n );\n\n // Step 4: Create null rates for currencies that failed both approaches\n const nullRates = this.#createNullRatesForCurrencies(\n Object.keys(failedCurrenciesFromFallback),\n );\n\n // Step 5: Merge all results - Price API rates take priority, then fallback, then null rates\n return {\n ...nullRates,\n ...ratesFromFallback,\n ...ratesPriceApi,\n };\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n return;\n }\n\n if (!this.#useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.#mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce<\n Record<string, string>\n >((acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n }, {});\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy(): void {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n return;\n }\n\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
|
|
1
|
+
{"version":3,"file":"CurrencyRateController.cjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { CurrencyRateControllerMethodActions } from './CurrencyRateController-method-action-types';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'setCurrentCurrency',\n 'updateExchangeRate',\n] as const;\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type CurrencyRateControllerGetStateAction = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions =\n | CurrencyRateControllerGetStateAction\n | CurrencyRateControllerMethodActions;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\nconst boundedPrecisionNumber = (value: number, precision = 9): number =>\n Number(value.toFixed(precision));\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\n/** Result from attempting to fetch rates from an API */\ntype FetchRatesResult = {\n /** Successfully fetched rates */\n rates: CurrencyRateState['currencyRates'];\n /** Currencies that failed and need fallback or null state */\n failedCurrencies: Record<string, string>;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n readonly #mutex = new Mutex();\n\n readonly #includeUsdRate: boolean;\n\n readonly #useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.#includeUsdRate = includeUsdRate;\n this.#useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.updateExchangeRate(nativeCurrencies);\n }\n\n /**\n * Attempts to fetch exchange rates from the primary Price API.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromPriceApi(\n nativeCurrenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n const rates: CurrencyRateState['currencyRates'] = {};\n let failedCurrencies: Record<string, string> = {};\n\n try {\n const response = await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.#includeUsdRate,\n cryptocurrencies: [...new Set(Object.values(nativeCurrenciesToFetch))],\n });\n\n Object.entries(nativeCurrenciesToFetch).forEach(\n ([nativeCurrency, fetchedCurrency]) => {\n const rate = response[fetchedCurrency.toLowerCase()];\n\n if (rate?.value) {\n rates[nativeCurrency] = {\n conversionDate: Date.now() / 1000,\n conversionRate: boundedPrecisionNumber(1 / rate.value),\n usdConversionRate: rate?.usd\n ? boundedPrecisionNumber(1 / rate.usd)\n : null,\n };\n } else {\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n },\n );\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n failedCurrencies = { ...nativeCurrenciesToFetch };\n }\n\n return { rates, failedCurrencies };\n }\n\n /**\n * Fetches exchange rates from the token prices service as a fallback.\n * This method is designed to never throw - all errors are handled internally\n * and result in currencies being marked as failed.\n *\n * @param currenciesToFetch - Map of native currencies that need fallback fetching.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromTokenPricesService(\n currenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n try {\n const rates: CurrencyRateState['currencyRates'] = {};\n const failedCurrencies: Record<string, string> = {};\n\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Build a map of nativeCurrency -> chainId for currencies to fetch\n const currencyToChainIds = Object.entries(currenciesToFetch).reduce<\n Record<string, { fetchedCurrency: string; chainId: Hex }>\n >((acc, [nativeCurrency, fetchedCurrency]) => {\n const matchingEntry = (\n Object.entries(networkConfigurations) as [Hex, NetworkConfiguration][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = { fetchedCurrency, chainId: matchingEntry[0] };\n } else {\n // No matching network configuration - mark as failed\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n return acc;\n }, {});\n\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n assets: [{ chainId, tokenAddress: nativeTokenAddress }],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices.find(\n (item) =>\n item.tokenAddress.toLowerCase() ===\n nativeTokenAddress.toLowerCase(),\n );\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price\n ? boundedPrecisionNumber(tokenPrice.price)\n : null,\n usdConversionRate: null,\n };\n }),\n );\n\n ratesResults.forEach((result, index) => {\n const [nativeCurrency, { fetchedCurrency, chainId }] =\n currencyToChainIdsEntries[index];\n\n if (result.status === 'fulfilled' && result.value.conversionRate) {\n rates[nativeCurrency] = {\n conversionDate: result.value.conversionDate,\n conversionRate: result.value.conversionRate,\n usdConversionRate: result.value.usdConversionRate,\n };\n } else {\n if (result.status === 'rejected') {\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n }\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n });\n\n return { rates, failedCurrencies };\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return all currencies as failed\n return { rates: {}, failedCurrencies: { ...currenciesToFetch } };\n }\n }\n\n /**\n * Creates null rate entries for currencies that couldn't be fetched.\n *\n * @param currencies - Array of currency symbols to create null entries for.\n * @returns Null rate entries for all provided currencies.\n */\n #createNullRatesForCurrencies(\n currencies: string[],\n ): CurrencyRateState['currencyRates'] {\n return currencies.reduce<CurrencyRateState['currencyRates']>(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {},\n );\n }\n\n /**\n * Fetches exchange rates with fallback logic.\n * First tries the Price API, then falls back to token prices service for any failed currencies.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @returns Exchange rates for all requested currencies.\n */\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n // Step 1: Try the Price API exchange rates first\n const {\n rates: ratesPriceApi,\n failedCurrencies: failedCurrenciesFromPriceApi,\n } = await this.#fetchRatesFromPriceApi(\n nativeCurrenciesToFetch,\n currentCurrency,\n );\n\n // Step 2: If all currencies succeeded, return early\n if (Object.keys(failedCurrenciesFromPriceApi).length === 0) {\n return ratesPriceApi;\n }\n\n // Step 3: Fallback using token prices service for failed currencies\n const {\n rates: ratesFromFallback,\n failedCurrencies: failedCurrenciesFromFallback,\n } = await this.#fetchRatesFromTokenPricesService(\n failedCurrenciesFromPriceApi,\n currentCurrency,\n );\n\n // Step 4: Create null rates for currencies that failed both approaches\n const nullRates = this.#createNullRatesForCurrencies(\n Object.keys(failedCurrenciesFromFallback),\n );\n\n // Step 5: Merge all results - Price API rates take priority, then fallback, then null rates\n return {\n ...nullRates,\n ...ratesFromFallback,\n ...ratesPriceApi,\n };\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (!this.#useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.#mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce<\n Record<string, string>\n >((acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n }, {});\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy(): void {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
|
|
@@ -64,20 +64,13 @@ export declare class CurrencyRateController extends CurrencyRateController_base<
|
|
|
64
64
|
* @param options.state - Initial state to set on this controller.
|
|
65
65
|
* @param options.useExternalServices - Feature Switch for using external services (default: true)
|
|
66
66
|
* @param options.tokenPricesService - An object in charge of retrieving token prices
|
|
67
|
-
* @param options.isDeprecated - Optional function that returns true to completely
|
|
68
|
-
* disable this controller (no requests, no state updates). When it returns
|
|
69
|
-
* `true`, `currencyRates` is reset to `{}` at construction and at every entry point,
|
|
70
|
-
* so no stale rates remain in state. The function is evaluated dynamically
|
|
71
|
-
* on each entry point so it can be toggled at runtime. Intended for use when
|
|
72
|
-
* a higher-level controller (e.g. AssetsController) supersedes this one.
|
|
73
67
|
*/
|
|
74
|
-
constructor({ includeUsdRate, interval, useExternalServices,
|
|
68
|
+
constructor({ includeUsdRate, interval, useExternalServices, messenger, state, tokenPricesService, }: {
|
|
75
69
|
includeUsdRate?: boolean;
|
|
76
70
|
interval?: number;
|
|
77
71
|
messenger: CurrencyRateMessenger;
|
|
78
72
|
state?: Partial<CurrencyRateState>;
|
|
79
73
|
useExternalServices?: () => boolean;
|
|
80
|
-
isDeprecated?: () => boolean;
|
|
81
74
|
tokenPricesService: AbstractTokenPricesService;
|
|
82
75
|
});
|
|
83
76
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyRateController.d.cts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,mCAAmC,EAAE,yDAAqD;AACxG,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAOtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAiBF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;
|
|
1
|
+
{"version":3,"file":"CurrencyRateController.d.cts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,mCAAmC,EAAE,yDAAqD;AACxG,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAOtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAiBF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;IASC;;;;;;;;;;OAUG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,mBAAgC,EAChC,SAAS,EACT,KAAK,EACL,kBAAkB,GACnB,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;QACpC,kBAAkB,EAAE,0BAA0B,CAAC;KAChD;IAkBD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4OhE;;;;OAIG;IACG,kBAAkB,CACtB,gBAAgB,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GACvC,OAAO,CAAC,IAAI,CAAC;IAyChB;;;;OAIG;IACM,OAAO,IAAI,IAAI;IAKxB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
|
|
@@ -64,20 +64,13 @@ export declare class CurrencyRateController extends CurrencyRateController_base<
|
|
|
64
64
|
* @param options.state - Initial state to set on this controller.
|
|
65
65
|
* @param options.useExternalServices - Feature Switch for using external services (default: true)
|
|
66
66
|
* @param options.tokenPricesService - An object in charge of retrieving token prices
|
|
67
|
-
* @param options.isDeprecated - Optional function that returns true to completely
|
|
68
|
-
* disable this controller (no requests, no state updates). When it returns
|
|
69
|
-
* `true`, `currencyRates` is reset to `{}` at construction and at every entry point,
|
|
70
|
-
* so no stale rates remain in state. The function is evaluated dynamically
|
|
71
|
-
* on each entry point so it can be toggled at runtime. Intended for use when
|
|
72
|
-
* a higher-level controller (e.g. AssetsController) supersedes this one.
|
|
73
67
|
*/
|
|
74
|
-
constructor({ includeUsdRate, interval, useExternalServices,
|
|
68
|
+
constructor({ includeUsdRate, interval, useExternalServices, messenger, state, tokenPricesService, }: {
|
|
75
69
|
includeUsdRate?: boolean;
|
|
76
70
|
interval?: number;
|
|
77
71
|
messenger: CurrencyRateMessenger;
|
|
78
72
|
state?: Partial<CurrencyRateState>;
|
|
79
73
|
useExternalServices?: () => boolean;
|
|
80
|
-
isDeprecated?: () => boolean;
|
|
81
74
|
tokenPricesService: AbstractTokenPricesService;
|
|
82
75
|
});
|
|
83
76
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyRateController.d.mts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,mCAAmC,EAAE,yDAAqD;AACxG,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAOtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAiBF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;
|
|
1
|
+
{"version":3,"file":"CurrencyRateController.d.mts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,mCAAmC,EAAE,yDAAqD;AACxG,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAOtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAiBF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;IASC;;;;;;;;;;OAUG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,mBAAgC,EAChC,SAAS,EACT,KAAK,EACL,kBAAkB,GACnB,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;QACpC,kBAAkB,EAAE,0BAA0B,CAAC;KAChD;IAkBD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4OhE;;;;OAIG;IACG,kBAAkB,CACtB,gBAAgB,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GACvC,OAAO,CAAC,IAAI,CAAC;IAyChB;;;;OAIG;IACM,OAAO,IAAI,IAAI;IAKxB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
|
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _CurrencyRateController_instances, _CurrencyRateController_mutex, _CurrencyRateController_includeUsdRate, _CurrencyRateController_useExternalServices, _CurrencyRateController_tokenPricesService,
|
|
12
|
+
var _CurrencyRateController_instances, _CurrencyRateController_mutex, _CurrencyRateController_includeUsdRate, _CurrencyRateController_useExternalServices, _CurrencyRateController_tokenPricesService, _CurrencyRateController_fetchRatesFromPriceApi, _CurrencyRateController_fetchRatesFromTokenPricesService, _CurrencyRateController_createNullRatesForCurrencies, _CurrencyRateController_fetchExchangeRatesWithFallback;
|
|
13
13
|
import { TESTNET_TICKER_SYMBOLS, FALL_BACK_VS_CURRENCY } from "@metamask/controller-utils";
|
|
14
14
|
import { StaticIntervalPollingController } from "@metamask/polling-controller";
|
|
15
15
|
import { Mutex } from "async-mutex";
|
|
@@ -59,14 +59,8 @@ export class CurrencyRateController extends StaticIntervalPollingController() {
|
|
|
59
59
|
* @param options.state - Initial state to set on this controller.
|
|
60
60
|
* @param options.useExternalServices - Feature Switch for using external services (default: true)
|
|
61
61
|
* @param options.tokenPricesService - An object in charge of retrieving token prices
|
|
62
|
-
* @param options.isDeprecated - Optional function that returns true to completely
|
|
63
|
-
* disable this controller (no requests, no state updates). When it returns
|
|
64
|
-
* `true`, `currencyRates` is reset to `{}` at construction and at every entry point,
|
|
65
|
-
* so no stale rates remain in state. The function is evaluated dynamically
|
|
66
|
-
* on each entry point so it can be toggled at runtime. Intended for use when
|
|
67
|
-
* a higher-level controller (e.g. AssetsController) supersedes this one.
|
|
68
62
|
*/
|
|
69
|
-
constructor({ includeUsdRate = false, interval = 180000, useExternalServices = () => true,
|
|
63
|
+
constructor({ includeUsdRate = false, interval = 180000, useExternalServices = () => true, messenger, state, tokenPricesService, }) {
|
|
70
64
|
super({
|
|
71
65
|
name,
|
|
72
66
|
metadata,
|
|
@@ -78,15 +72,10 @@ export class CurrencyRateController extends StaticIntervalPollingController() {
|
|
|
78
72
|
_CurrencyRateController_includeUsdRate.set(this, void 0);
|
|
79
73
|
_CurrencyRateController_useExternalServices.set(this, void 0);
|
|
80
74
|
_CurrencyRateController_tokenPricesService.set(this, void 0);
|
|
81
|
-
_CurrencyRateController_isDeprecated.set(this, void 0);
|
|
82
75
|
__classPrivateFieldSet(this, _CurrencyRateController_includeUsdRate, includeUsdRate, "f");
|
|
83
76
|
__classPrivateFieldSet(this, _CurrencyRateController_useExternalServices, useExternalServices, "f");
|
|
84
77
|
this.setIntervalLength(interval);
|
|
85
78
|
__classPrivateFieldSet(this, _CurrencyRateController_tokenPricesService, tokenPricesService, "f");
|
|
86
|
-
__classPrivateFieldSet(this, _CurrencyRateController_isDeprecated, isDeprecated, "f");
|
|
87
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
88
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
89
|
-
}
|
|
90
79
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
91
80
|
}
|
|
92
81
|
/**
|
|
@@ -95,10 +84,6 @@ export class CurrencyRateController extends StaticIntervalPollingController() {
|
|
|
95
84
|
* @param currentCurrency - ISO 4217 currency code.
|
|
96
85
|
*/
|
|
97
86
|
async setCurrentCurrency(currentCurrency) {
|
|
98
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
99
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
87
|
const releaseLock = await __classPrivateFieldGet(this, _CurrencyRateController_mutex, "f").acquire();
|
|
103
88
|
const nativeCurrencies = Object.keys(this.state.currencyRates);
|
|
104
89
|
try {
|
|
@@ -122,10 +107,6 @@ export class CurrencyRateController extends StaticIntervalPollingController() {
|
|
|
122
107
|
* @param nativeCurrencies - The native currency symbols to fetch exchange rates for.
|
|
123
108
|
*/
|
|
124
109
|
async updateExchangeRate(nativeCurrencies) {
|
|
125
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
126
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
110
|
if (!__classPrivateFieldGet(this, _CurrencyRateController_useExternalServices, "f").call(this)) {
|
|
130
111
|
return;
|
|
131
112
|
}
|
|
@@ -175,21 +156,10 @@ export class CurrencyRateController extends StaticIntervalPollingController() {
|
|
|
175
156
|
* @param input.nativeCurrencies - The native currency symbols to poll prices for.
|
|
176
157
|
*/
|
|
177
158
|
async _executePoll({ nativeCurrencies, }) {
|
|
178
|
-
if (__classPrivateFieldGet(this, _CurrencyRateController_isDeprecated, "f").call(this)) {
|
|
179
|
-
__classPrivateFieldGet(this, _CurrencyRateController_instances, "m", _CurrencyRateController_enforceDisabledState).call(this);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
159
|
await this.updateExchangeRate(nativeCurrencies);
|
|
183
160
|
}
|
|
184
161
|
}
|
|
185
|
-
_CurrencyRateController_mutex = new WeakMap(), _CurrencyRateController_includeUsdRate = new WeakMap(), _CurrencyRateController_useExternalServices = new WeakMap(), _CurrencyRateController_tokenPricesService = new WeakMap(),
|
|
186
|
-
if (Object.keys(this.state.currencyRates).length === 0) {
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
this.update((state) => {
|
|
190
|
-
state.currencyRates = {};
|
|
191
|
-
});
|
|
192
|
-
}, _CurrencyRateController_fetchRatesFromPriceApi =
|
|
162
|
+
_CurrencyRateController_mutex = new WeakMap(), _CurrencyRateController_includeUsdRate = new WeakMap(), _CurrencyRateController_useExternalServices = new WeakMap(), _CurrencyRateController_tokenPricesService = new WeakMap(), _CurrencyRateController_instances = new WeakSet(), _CurrencyRateController_fetchRatesFromPriceApi =
|
|
193
163
|
/**
|
|
194
164
|
* Attempts to fetch exchange rates from the primary Price API.
|
|
195
165
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyRateController.mjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { CurrencyRateControllerMethodActions } from './CurrencyRateController-method-action-types';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'setCurrentCurrency',\n 'updateExchangeRate',\n] as const;\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type CurrencyRateControllerGetStateAction = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions =\n | CurrencyRateControllerGetStateAction\n | CurrencyRateControllerMethodActions;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\nconst boundedPrecisionNumber = (value: number, precision = 9): number =>\n Number(value.toFixed(precision));\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\n/** Result from attempting to fetch rates from an API */\ntype FetchRatesResult = {\n /** Successfully fetched rates */\n rates: CurrencyRateState['currencyRates'];\n /** Currencies that failed and need fallback or null state */\n failedCurrencies: Record<string, string>;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n readonly #mutex = new Mutex();\n\n readonly #includeUsdRate: boolean;\n\n readonly #useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n readonly #isDeprecated: () => boolean;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n * @param options.isDeprecated - Optional function that returns true to completely\n * disable this controller (no requests, no state updates). When it returns\n * `true`, `currencyRates` is reset to `{}` at construction and at every entry point,\n * so no stale rates remain in state. The function is evaluated dynamically\n * on each entry point so it can be toggled at runtime. Intended for use when\n * a higher-level controller (e.g. AssetsController) supersedes this one.\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n isDeprecated = (): boolean => false,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n isDeprecated?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.#includeUsdRate = includeUsdRate;\n this.#useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n this.#isDeprecated = isDeprecated;\n\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n }\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Clears all persisted `currencyRates` so that no stale rates remain in state.\n *\n * Called from every entry point when `isDeprecated()` is true so that a\n * runtime toggle propagates to state immediately, even if the controller was\n * originally constructed while it was enabled. The update is skipped when\n * `currencyRates` is already empty to avoid emitting redundant state changes.\n */\n #enforceDisabledState(): void {\n if (Object.keys(this.state.currencyRates).length === 0) {\n return;\n }\n this.update((state) => {\n state.currencyRates = {};\n });\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string): Promise<void> {\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n return;\n }\n\n const releaseLock = await this.#mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.updateExchangeRate(nativeCurrencies);\n }\n\n /**\n * Attempts to fetch exchange rates from the primary Price API.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromPriceApi(\n nativeCurrenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n const rates: CurrencyRateState['currencyRates'] = {};\n let failedCurrencies: Record<string, string> = {};\n\n try {\n const response = await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.#includeUsdRate,\n cryptocurrencies: [...new Set(Object.values(nativeCurrenciesToFetch))],\n });\n\n Object.entries(nativeCurrenciesToFetch).forEach(\n ([nativeCurrency, fetchedCurrency]) => {\n const rate = response[fetchedCurrency.toLowerCase()];\n\n if (rate?.value) {\n rates[nativeCurrency] = {\n conversionDate: Date.now() / 1000,\n conversionRate: boundedPrecisionNumber(1 / rate.value),\n usdConversionRate: rate?.usd\n ? boundedPrecisionNumber(1 / rate.usd)\n : null,\n };\n } else {\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n },\n );\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n failedCurrencies = { ...nativeCurrenciesToFetch };\n }\n\n return { rates, failedCurrencies };\n }\n\n /**\n * Fetches exchange rates from the token prices service as a fallback.\n * This method is designed to never throw - all errors are handled internally\n * and result in currencies being marked as failed.\n *\n * @param currenciesToFetch - Map of native currencies that need fallback fetching.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromTokenPricesService(\n currenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n try {\n const rates: CurrencyRateState['currencyRates'] = {};\n const failedCurrencies: Record<string, string> = {};\n\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Build a map of nativeCurrency -> chainId for currencies to fetch\n const currencyToChainIds = Object.entries(currenciesToFetch).reduce<\n Record<string, { fetchedCurrency: string; chainId: Hex }>\n >((acc, [nativeCurrency, fetchedCurrency]) => {\n const matchingEntry = (\n Object.entries(networkConfigurations) as [Hex, NetworkConfiguration][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = { fetchedCurrency, chainId: matchingEntry[0] };\n } else {\n // No matching network configuration - mark as failed\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n return acc;\n }, {});\n\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n assets: [{ chainId, tokenAddress: nativeTokenAddress }],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices.find(\n (item) =>\n item.tokenAddress.toLowerCase() ===\n nativeTokenAddress.toLowerCase(),\n );\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price\n ? boundedPrecisionNumber(tokenPrice.price)\n : null,\n usdConversionRate: null,\n };\n }),\n );\n\n ratesResults.forEach((result, index) => {\n const [nativeCurrency, { fetchedCurrency, chainId }] =\n currencyToChainIdsEntries[index];\n\n if (result.status === 'fulfilled' && result.value.conversionRate) {\n rates[nativeCurrency] = {\n conversionDate: result.value.conversionDate,\n conversionRate: result.value.conversionRate,\n usdConversionRate: result.value.usdConversionRate,\n };\n } else {\n if (result.status === 'rejected') {\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n }\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n });\n\n return { rates, failedCurrencies };\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return all currencies as failed\n return { rates: {}, failedCurrencies: { ...currenciesToFetch } };\n }\n }\n\n /**\n * Creates null rate entries for currencies that couldn't be fetched.\n *\n * @param currencies - Array of currency symbols to create null entries for.\n * @returns Null rate entries for all provided currencies.\n */\n #createNullRatesForCurrencies(\n currencies: string[],\n ): CurrencyRateState['currencyRates'] {\n return currencies.reduce<CurrencyRateState['currencyRates']>(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {},\n );\n }\n\n /**\n * Fetches exchange rates with fallback logic.\n * First tries the Price API, then falls back to token prices service for any failed currencies.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @returns Exchange rates for all requested currencies.\n */\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n // Step 1: Try the Price API exchange rates first\n const {\n rates: ratesPriceApi,\n failedCurrencies: failedCurrenciesFromPriceApi,\n } = await this.#fetchRatesFromPriceApi(\n nativeCurrenciesToFetch,\n currentCurrency,\n );\n\n // Step 2: If all currencies succeeded, return early\n if (Object.keys(failedCurrenciesFromPriceApi).length === 0) {\n return ratesPriceApi;\n }\n\n // Step 3: Fallback using token prices service for failed currencies\n const {\n rates: ratesFromFallback,\n failedCurrencies: failedCurrenciesFromFallback,\n } = await this.#fetchRatesFromTokenPricesService(\n failedCurrenciesFromPriceApi,\n currentCurrency,\n );\n\n // Step 4: Create null rates for currencies that failed both approaches\n const nullRates = this.#createNullRatesForCurrencies(\n Object.keys(failedCurrenciesFromFallback),\n );\n\n // Step 5: Merge all results - Price API rates take priority, then fallback, then null rates\n return {\n ...nullRates,\n ...ratesFromFallback,\n ...ratesPriceApi,\n };\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n return;\n }\n\n if (!this.#useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.#mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce<\n Record<string, string>\n >((acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n }, {});\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy(): void {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n if (this.#isDeprecated()) {\n this.#enforceDisabledState();\n return;\n }\n\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
|
|
1
|
+
{"version":3,"file":"CurrencyRateController.mjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { CurrencyRateControllerMethodActions } from './CurrencyRateController-method-action-types';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'setCurrentCurrency',\n 'updateExchangeRate',\n] as const;\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type CurrencyRateControllerGetStateAction = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions =\n | CurrencyRateControllerGetStateAction\n | CurrencyRateControllerMethodActions;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\nconst boundedPrecisionNumber = (value: number, precision = 9): number =>\n Number(value.toFixed(precision));\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\n/** Result from attempting to fetch rates from an API */\ntype FetchRatesResult = {\n /** Successfully fetched rates */\n rates: CurrencyRateState['currencyRates'];\n /** Currencies that failed and need fallback or null state */\n failedCurrencies: Record<string, string>;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n readonly #mutex = new Mutex();\n\n readonly #includeUsdRate: boolean;\n\n readonly #useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.#includeUsdRate = includeUsdRate;\n this.#useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.updateExchangeRate(nativeCurrencies);\n }\n\n /**\n * Attempts to fetch exchange rates from the primary Price API.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromPriceApi(\n nativeCurrenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n const rates: CurrencyRateState['currencyRates'] = {};\n let failedCurrencies: Record<string, string> = {};\n\n try {\n const response = await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.#includeUsdRate,\n cryptocurrencies: [...new Set(Object.values(nativeCurrenciesToFetch))],\n });\n\n Object.entries(nativeCurrenciesToFetch).forEach(\n ([nativeCurrency, fetchedCurrency]) => {\n const rate = response[fetchedCurrency.toLowerCase()];\n\n if (rate?.value) {\n rates[nativeCurrency] = {\n conversionDate: Date.now() / 1000,\n conversionRate: boundedPrecisionNumber(1 / rate.value),\n usdConversionRate: rate?.usd\n ? boundedPrecisionNumber(1 / rate.usd)\n : null,\n };\n } else {\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n },\n );\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n failedCurrencies = { ...nativeCurrenciesToFetch };\n }\n\n return { rates, failedCurrencies };\n }\n\n /**\n * Fetches exchange rates from the token prices service as a fallback.\n * This method is designed to never throw - all errors are handled internally\n * and result in currencies being marked as failed.\n *\n * @param currenciesToFetch - Map of native currencies that need fallback fetching.\n * @param currentCurrency - The current fiat currency to get rates for.\n * @returns Object containing successful rates and currencies that failed.\n */\n async #fetchRatesFromTokenPricesService(\n currenciesToFetch: Record<string, string>,\n currentCurrency: string,\n ): Promise<FetchRatesResult> {\n try {\n const rates: CurrencyRateState['currencyRates'] = {};\n const failedCurrencies: Record<string, string> = {};\n\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Build a map of nativeCurrency -> chainId for currencies to fetch\n const currencyToChainIds = Object.entries(currenciesToFetch).reduce<\n Record<string, { fetchedCurrency: string; chainId: Hex }>\n >((acc, [nativeCurrency, fetchedCurrency]) => {\n const matchingEntry = (\n Object.entries(networkConfigurations) as [Hex, NetworkConfiguration][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = { fetchedCurrency, chainId: matchingEntry[0] };\n } else {\n // No matching network configuration - mark as failed\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n return acc;\n }, {});\n\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n assets: [{ chainId, tokenAddress: nativeTokenAddress }],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices.find(\n (item) =>\n item.tokenAddress.toLowerCase() ===\n nativeTokenAddress.toLowerCase(),\n );\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price\n ? boundedPrecisionNumber(tokenPrice.price)\n : null,\n usdConversionRate: null,\n };\n }),\n );\n\n ratesResults.forEach((result, index) => {\n const [nativeCurrency, { fetchedCurrency, chainId }] =\n currencyToChainIdsEntries[index];\n\n if (result.status === 'fulfilled' && result.value.conversionRate) {\n rates[nativeCurrency] = {\n conversionDate: result.value.conversionDate,\n conversionRate: result.value.conversionRate,\n usdConversionRate: result.value.usdConversionRate,\n };\n } else {\n if (result.status === 'rejected') {\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n }\n failedCurrencies[nativeCurrency] = fetchedCurrency;\n }\n });\n\n return { rates, failedCurrencies };\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return all currencies as failed\n return { rates: {}, failedCurrencies: { ...currenciesToFetch } };\n }\n }\n\n /**\n * Creates null rate entries for currencies that couldn't be fetched.\n *\n * @param currencies - Array of currency symbols to create null entries for.\n * @returns Null rate entries for all provided currencies.\n */\n #createNullRatesForCurrencies(\n currencies: string[],\n ): CurrencyRateState['currencyRates'] {\n return currencies.reduce<CurrencyRateState['currencyRates']>(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {},\n );\n }\n\n /**\n * Fetches exchange rates with fallback logic.\n * First tries the Price API, then falls back to token prices service for any failed currencies.\n *\n * @param nativeCurrenciesToFetch - Map of native currency to the currency symbol to fetch.\n * @returns Exchange rates for all requested currencies.\n */\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n // Step 1: Try the Price API exchange rates first\n const {\n rates: ratesPriceApi,\n failedCurrencies: failedCurrenciesFromPriceApi,\n } = await this.#fetchRatesFromPriceApi(\n nativeCurrenciesToFetch,\n currentCurrency,\n );\n\n // Step 2: If all currencies succeeded, return early\n if (Object.keys(failedCurrenciesFromPriceApi).length === 0) {\n return ratesPriceApi;\n }\n\n // Step 3: Fallback using token prices service for failed currencies\n const {\n rates: ratesFromFallback,\n failedCurrencies: failedCurrenciesFromFallback,\n } = await this.#fetchRatesFromTokenPricesService(\n failedCurrenciesFromPriceApi,\n currentCurrency,\n );\n\n // Step 4: Create null rates for currencies that failed both approaches\n const nullRates = this.#createNullRatesForCurrencies(\n Object.keys(failedCurrenciesFromFallback),\n );\n\n // Step 5: Merge all results - Price API rates take priority, then fallback, then null rates\n return {\n ...nullRates,\n ...ratesFromFallback,\n ...ratesPriceApi,\n };\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (!this.#useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.#mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce<\n Record<string, string>\n >((acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n }, {});\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy(): void {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/assets-controllers",
|
|
3
|
-
"version": "109.1.0-preview-
|
|
3
|
+
"version": "109.1.0-preview-8cbb66949",
|
|
4
4
|
"description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|