@metamask/assets-controllers 2.0.0 → 3.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 CHANGED
@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.0.0]
10
+ ### Changed
11
+ - **BREAKING:** A new private property, controlled by the `start` and `stop` methods, is added to the CurrencyRateController: `enabled`. When this is false, no network requests will be made from the controller. Previously, setNativeCurrency or setCurrentCurrency would trigger a network request. That is now prevented if `enabled` is false. ([#1002](https://github.com/MetaMask/controllers/pull/1002))
12
+
13
+ ### Fixed
14
+ - The TokenRatesController no longer overwrites the `disabled` config property passed to the constructor, allowing the controller to be instantiated with `config.disabled` set to either true or false. ([#1002](https://github.com/MetaMask/controllers/pull/1002))
15
+ - This package will now warn if a required package is not present ([#1003](https://github.com/MetaMask/controllers/pull/1003))
16
+
9
17
  ## [2.0.0]
10
18
  ### Changed
11
19
  - **BREAKING:** Update `onNetworkStateChange`, a constructor option for several controllers, to take an object with a `providerConfig` property instead of `provider` ([#995](https://github.com/MetaMask/controllers/pull/995))
@@ -36,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
36
44
  ### Changed
37
45
  - Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/controllers/pull/845))
38
46
 
39
- [Unreleased]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@2.0.0...HEAD
47
+ [Unreleased]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@3.0.0...HEAD
48
+ [3.0.0]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@2.0.0...@metamask/assets-controllers@3.0.0
40
49
  [2.0.0]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@1.0.1...@metamask/assets-controllers@2.0.0
41
50
  [1.0.1]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@1.0.0...@metamask/assets-controllers@1.0.1
42
51
  [1.0.0]: https://github.com/MetaMask/controllers/releases/tag/@metamask/assets-controllers@1.0.0
@@ -35,6 +35,7 @@ declare type CurrencyRateMessenger = RestrictedControllerMessenger<typeof name,
35
35
  * asset to the user's preferred currency.
36
36
  */
37
37
  export declare class CurrencyRateController extends BaseControllerV2<typeof name, CurrencyRateState, CurrencyRateMessenger> {
38
+ #private;
38
39
  private mutex;
39
40
  private intervalId?;
40
41
  private intervalDelay;
@@ -8,6 +8,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
12
+ if (kind === "m") throw new TypeError("Private method is not writable");
13
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
14
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
15
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
16
+ };
17
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
18
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
19
+ 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");
20
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
21
+ };
22
+ var _CurrencyRateController_enabled;
11
23
  Object.defineProperty(exports, "__esModule", { value: true });
12
24
  exports.CurrencyRateController = void 0;
13
25
  const async_mutex_1 = require("async-mutex");
@@ -56,15 +68,21 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
56
68
  state: Object.assign(Object.assign({}, defaultState), state),
57
69
  });
58
70
  this.mutex = new async_mutex_1.Mutex();
71
+ /**
72
+ * A boolean that controls whether or not network requests can be made by the controller
73
+ */
74
+ _CurrencyRateController_enabled.set(this, void 0);
59
75
  this.includeUsdRate = includeUsdRate;
60
76
  this.intervalDelay = interval;
61
77
  this.fetchExchangeRate = fetchExchangeRate;
78
+ __classPrivateFieldSet(this, _CurrencyRateController_enabled, false, "f");
62
79
  }
63
80
  /**
64
81
  * Start polling for the currency rate.
65
82
  */
66
83
  start() {
67
84
  return __awaiter(this, void 0, void 0, function* () {
85
+ __classPrivateFieldSet(this, _CurrencyRateController_enabled, true, "f");
68
86
  yield this.startPolling();
69
87
  });
70
88
  }
@@ -72,6 +90,7 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
72
90
  * Stop polling for the currency rate.
73
91
  */
74
92
  stop() {
93
+ __classPrivateFieldSet(this, _CurrencyRateController_enabled, false, "f");
75
94
  this.stopPolling();
76
95
  }
77
96
  /**
@@ -121,9 +140,9 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
121
140
  return __awaiter(this, void 0, void 0, function* () {
122
141
  this.stopPolling();
123
142
  // TODO: Expose polling currency rate update errors
124
- yield (0, controller_utils_1.safelyExecute)(() => this.updateExchangeRate());
143
+ yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { return yield this.updateExchangeRate(); }));
125
144
  this.intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
126
- yield (0, controller_utils_1.safelyExecute)(() => this.updateExchangeRate());
145
+ yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { return yield this.updateExchangeRate(); }));
127
146
  }), this.intervalDelay);
128
147
  });
129
148
  }
@@ -134,6 +153,10 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
134
153
  */
135
154
  updateExchangeRate() {
136
155
  return __awaiter(this, void 0, void 0, function* () {
156
+ if (!__classPrivateFieldGet(this, _CurrencyRateController_enabled, "f")) {
157
+ console.info('[CurrencyRateController] Not updating exchange rate since network requests have been disabled');
158
+ return this.state;
159
+ }
137
160
  const releaseLock = yield this.mutex.acquire();
138
161
  const { currentCurrency: stateCurrentCurrency, nativeCurrency: stateNativeCurrency, pendingCurrentCurrency, pendingNativeCurrency, } = this.state;
139
162
  let conversionDate = null;
@@ -153,7 +176,9 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
153
176
  // a null conversionRate either way.
154
177
  currentCurrency !== '' &&
155
178
  nativeCurrency !== '') {
156
- ({ conversionRate, usdConversionRate } = yield this.fetchExchangeRate(currentCurrency, nativeCurrencyForExchangeRate, this.includeUsdRate));
179
+ const fetchExchangeRateResponse = yield this.fetchExchangeRate(currentCurrency, nativeCurrencyForExchangeRate, this.includeUsdRate);
180
+ conversionRate = fetchExchangeRateResponse.conversionRate;
181
+ usdConversionRate = fetchExchangeRateResponse.usdConversionRate;
157
182
  conversionDate = Date.now() / 1000;
158
183
  }
159
184
  }
@@ -189,5 +214,6 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
189
214
  }
190
215
  }
191
216
  exports.CurrencyRateController = CurrencyRateController;
217
+ _CurrencyRateController_enabled = new WeakMap();
192
218
  exports.default = CurrencyRateController;
193
219
  //# sourceMappingURL=CurrencyRateController.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.js","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mutex } from 'async-mutex';\nimport type { Patch } from 'immer';\nimport {\n BaseControllerV2,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n safelyExecute,\n} from '@metamask/controller-utils';\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare';\n\n/**\n * @type CurrencyRateState\n * @property conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property nativeCurrency - Symbol for the base asset used for conversion\n * @property pendingCurrentCurrency - The currency being switched to\n * @property pendingNativeCurrency - The base asset currency being switched to\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n conversionDate: number | null;\n conversionRate: number | null;\n currentCurrency: string;\n nativeCurrency: string;\n pendingCurrentCurrency: string | null;\n pendingNativeCurrency: string | null;\n usdConversionRate: number | null;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = {\n type: `${typeof name}:stateChange`;\n payload: [CurrencyRateState, Patch[]];\n};\n\nexport type GetCurrencyRateState = {\n type: `${typeof name}:getState`;\n handler: () => CurrencyRateState;\n};\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n GetCurrencyRateState,\n CurrencyRateStateChange,\n never,\n never\n>;\n\nconst metadata = {\n conversionDate: { persist: true, anonymous: true },\n conversionRate: { persist: true, anonymous: true },\n currentCurrency: { persist: true, anonymous: true },\n nativeCurrency: { persist: true, anonymous: true },\n pendingCurrentCurrency: { persist: false, anonymous: true },\n pendingNativeCurrency: { persist: false, anonymous: true },\n usdConversionRate: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n conversionDate: 0,\n conversionRate: 0,\n currentCurrency: 'usd',\n nativeCurrency: 'ETH',\n pendingCurrentCurrency: null,\n pendingNativeCurrency: null,\n usdConversionRate: null,\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 BaseControllerV2<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private mutex = new Mutex();\n\n private intervalId?: ReturnType<typeof setTimeout>;\n\n private intervalDelay;\n\n private fetchExchangeRate;\n\n private includeUsdRate;\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 messaging system.\n * @param options.state - Initial state to set on this controller.\n * @param options.fetchExchangeRate - Fetches the exchange rate from an external API. This option is primarily meant for use in unit tests.\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n messenger,\n state,\n fetchExchangeRate = defaultFetchExchangeRate,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n fetchExchangeRate?: typeof defaultFetchExchangeRate;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.intervalDelay = interval;\n this.fetchExchangeRate = fetchExchangeRate;\n }\n\n /**\n * Start polling for the currency rate.\n */\n async start() {\n await this.startPolling();\n }\n\n /**\n * Stop polling for the currency rate.\n */\n stop() {\n this.stopPolling();\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopPolling();\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n this.update((state) => {\n state.pendingCurrentCurrency = currentCurrency;\n });\n await this.updateExchangeRate();\n }\n\n /**\n * Sets a new native currency.\n *\n * @param symbol - Symbol for the base asset.\n */\n async setNativeCurrency(symbol: string) {\n this.update((state) => {\n state.pendingNativeCurrency = symbol;\n });\n await this.updateExchangeRate();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n private async startPolling(): Promise<void> {\n this.stopPolling();\n // TODO: Expose polling currency rate update errors\n await safelyExecute(() => this.updateExchangeRate());\n this.intervalId = setInterval(async () => {\n await safelyExecute(() => this.updateExchangeRate());\n }, this.intervalDelay);\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @returns The controller state.\n */\n async updateExchangeRate(): Promise<CurrencyRateState | void> {\n const releaseLock = await this.mutex.acquire();\n const {\n currentCurrency: stateCurrentCurrency,\n nativeCurrency: stateNativeCurrency,\n pendingCurrentCurrency,\n pendingNativeCurrency,\n } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n const currentCurrency = pendingCurrentCurrency ?? stateCurrentCurrency;\n const nativeCurrency = pendingNativeCurrency ?? stateNativeCurrency;\n\n // For preloaded testnets (Rinkeby, Ropsten, Goerli, Kovan) we want to fetch exchange rate for real ETH.\n const nativeCurrencyForExchangeRate = Object.values(\n TESTNET_TICKER_SYMBOLS,\n ).includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY // ETH\n : nativeCurrency;\n\n try {\n if (\n currentCurrency &&\n nativeCurrency &&\n // if either currency is an empty string we can skip the comparison\n // because it will result in an error from the api and ultimately\n // a null conversionRate either way.\n currentCurrency !== '' &&\n nativeCurrency !== ''\n ) {\n ({ conversionRate, usdConversionRate } = await this.fetchExchangeRate(\n currentCurrency,\n nativeCurrencyForExchangeRate,\n this.includeUsdRate,\n ));\n conversionDate = Date.now() / 1000;\n }\n } catch (error) {\n if (\n !(\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n )\n ) {\n throw error;\n }\n } finally {\n try {\n this.update(() => {\n return {\n conversionDate,\n conversionRate,\n // we currently allow and handle an empty string as a valid nativeCurrency\n // in cases where a user has not entered a native ticker symbol for a custom network\n // currentCurrency is not from user input but this protects us from unexpected changes.\n nativeCurrency,\n currentCurrency,\n pendingCurrentCurrency: null,\n pendingNativeCurrency: null,\n usdConversionRate,\n };\n });\n } finally {\n releaseLock();\n }\n }\n return this.state;\n }\n}\n\nexport default CurrencyRateController;\n"]}
1
+ {"version":3,"file":"CurrencyRateController.js","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mutex } from 'async-mutex';\nimport type { Patch } from 'immer';\nimport {\n BaseControllerV2,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n safelyExecute,\n} from '@metamask/controller-utils';\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare';\n\n/**\n * @type CurrencyRateState\n * @property conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property nativeCurrency - Symbol for the base asset used for conversion\n * @property pendingCurrentCurrency - The currency being switched to\n * @property pendingNativeCurrency - The base asset currency being switched to\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n conversionDate: number | null;\n conversionRate: number | null;\n currentCurrency: string;\n nativeCurrency: string;\n pendingCurrentCurrency: string | null;\n pendingNativeCurrency: string | null;\n usdConversionRate: number | null;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = {\n type: `${typeof name}:stateChange`;\n payload: [CurrencyRateState, Patch[]];\n};\n\nexport type GetCurrencyRateState = {\n type: `${typeof name}:getState`;\n handler: () => CurrencyRateState;\n};\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n GetCurrencyRateState,\n CurrencyRateStateChange,\n never,\n never\n>;\n\nconst metadata = {\n conversionDate: { persist: true, anonymous: true },\n conversionRate: { persist: true, anonymous: true },\n currentCurrency: { persist: true, anonymous: true },\n nativeCurrency: { persist: true, anonymous: true },\n pendingCurrentCurrency: { persist: false, anonymous: true },\n pendingNativeCurrency: { persist: false, anonymous: true },\n usdConversionRate: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n conversionDate: 0,\n conversionRate: 0,\n currentCurrency: 'usd',\n nativeCurrency: 'ETH',\n pendingCurrentCurrency: null,\n pendingNativeCurrency: null,\n usdConversionRate: null,\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 BaseControllerV2<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private mutex = new Mutex();\n\n private intervalId?: ReturnType<typeof setTimeout>;\n\n private intervalDelay;\n\n private fetchExchangeRate;\n\n private includeUsdRate;\n\n /**\n * A boolean that controls whether or not network requests can be made by the controller\n */\n #enabled;\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 messaging system.\n * @param options.state - Initial state to set on this controller.\n * @param options.fetchExchangeRate - Fetches the exchange rate from an external API. This option is primarily meant for use in unit tests.\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n messenger,\n state,\n fetchExchangeRate = defaultFetchExchangeRate,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n fetchExchangeRate?: typeof defaultFetchExchangeRate;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.intervalDelay = interval;\n this.fetchExchangeRate = fetchExchangeRate;\n this.#enabled = false;\n }\n\n /**\n * Start polling for the currency rate.\n */\n async start() {\n this.#enabled = true;\n\n await this.startPolling();\n }\n\n /**\n * Stop polling for the currency rate.\n */\n stop() {\n this.#enabled = false;\n\n this.stopPolling();\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopPolling();\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n this.update((state) => {\n state.pendingCurrentCurrency = currentCurrency;\n });\n await this.updateExchangeRate();\n }\n\n /**\n * Sets a new native currency.\n *\n * @param symbol - Symbol for the base asset.\n */\n async setNativeCurrency(symbol: string) {\n this.update((state) => {\n state.pendingNativeCurrency = symbol;\n });\n await this.updateExchangeRate();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n private async startPolling(): Promise<void> {\n this.stopPolling();\n // TODO: Expose polling currency rate update errors\n\n await safelyExecute(async () => await this.updateExchangeRate());\n\n this.intervalId = setInterval(async () => {\n await safelyExecute(async () => await this.updateExchangeRate());\n }, this.intervalDelay);\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @returns The controller state.\n */\n async updateExchangeRate(): Promise<CurrencyRateState | void> {\n if (!this.#enabled) {\n console.info(\n '[CurrencyRateController] Not updating exchange rate since network requests have been disabled',\n );\n return this.state;\n }\n const releaseLock = await this.mutex.acquire();\n const {\n currentCurrency: stateCurrentCurrency,\n nativeCurrency: stateNativeCurrency,\n pendingCurrentCurrency,\n pendingNativeCurrency,\n } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n const currentCurrency = pendingCurrentCurrency ?? stateCurrentCurrency;\n const nativeCurrency = pendingNativeCurrency ?? stateNativeCurrency;\n\n // For preloaded testnets (Rinkeby, Ropsten, Goerli, Kovan) we want to fetch exchange rate for real ETH.\n const nativeCurrencyForExchangeRate = Object.values(\n TESTNET_TICKER_SYMBOLS,\n ).includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY // ETH\n : nativeCurrency;\n\n try {\n if (\n currentCurrency &&\n nativeCurrency &&\n // if either currency is an empty string we can skip the comparison\n // because it will result in an error from the api and ultimately\n // a null conversionRate either way.\n currentCurrency !== '' &&\n nativeCurrency !== ''\n ) {\n const fetchExchangeRateResponse = await this.fetchExchangeRate(\n currentCurrency,\n nativeCurrencyForExchangeRate,\n this.includeUsdRate,\n );\n\n conversionRate = fetchExchangeRateResponse.conversionRate;\n usdConversionRate = fetchExchangeRateResponse.usdConversionRate;\n conversionDate = Date.now() / 1000;\n }\n } catch (error) {\n if (\n !(\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n )\n ) {\n throw error;\n }\n } finally {\n try {\n this.update(() => {\n return {\n conversionDate,\n conversionRate,\n // we currently allow and handle an empty string as a valid nativeCurrency\n // in cases where a user has not entered a native ticker symbol for a custom network\n // currentCurrency is not from user input but this protects us from unexpected changes.\n nativeCurrency,\n currentCurrency,\n pendingCurrentCurrency: null,\n pendingNativeCurrency: null,\n usdConversionRate,\n };\n });\n } finally {\n releaseLock();\n }\n }\n return this.state;\n }\n}\n\nexport default CurrencyRateController;\n"]}
@@ -71,7 +71,7 @@ class TokenRatesController extends base_controller_1.BaseController {
71
71
  */
72
72
  this.name = 'TokenRatesController';
73
73
  this.defaultConfig = {
74
- disabled: true,
74
+ disabled: false,
75
75
  interval: 3 * 60 * 1000,
76
76
  nativeCurrency: 'eth',
77
77
  chainId: '',
@@ -82,7 +82,9 @@ class TokenRatesController extends base_controller_1.BaseController {
82
82
  contractExchangeRates: {},
83
83
  };
84
84
  this.initialize();
85
- this.configure({ disabled: false }, false, false);
85
+ if (config === null || config === void 0 ? void 0 : config.disabled) {
86
+ this.configure({ disabled: true }, false, false);
87
+ }
86
88
  onTokensStateChange(({ tokens, detectedTokens }) => {
87
89
  this.configure({ tokens: [...tokens, ...detectedTokens] });
88
90
  });
@@ -1 +1 @@
1
- {"version":3,"file":"TokenRatesController.js","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n BaseConfig,\n BaseState,\n} from '@metamask/base-controller';\nimport {\n safelyExecute,\n handleFetch,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { NetworkState } from '@metamask/network-controller';\nimport { fetchExchangeRate as fetchNativeExchangeRate } from './crypto-compare';\nimport type { TokensState } from './TokensController';\nimport type { CurrencyRateState } from './CurrencyRateController';\n\n/**\n * @type CoinGeckoResponse\n *\n * CoinGecko API response representation\n */\nexport interface CoinGeckoResponse {\n [address: string]: {\n [currency: string]: number;\n };\n}\n/**\n * @type CoinGeckoPlatform\n *\n * CoinGecko supported platform API representation\n */\nexport interface CoinGeckoPlatform {\n id: string;\n chain_identifier: null | number;\n name: string;\n shortname: string;\n}\n\n/**\n * @type Token\n *\n * Token representation\n * @property address - Hex address of the token contract\n * @property decimals - Number of decimals the token uses\n * @property symbol - Symbol of the token\n * @property image - Image of the token, url or bit32 image\n */\nexport interface Token {\n address: string;\n decimals: number;\n symbol: string;\n aggregators?: string[];\n image?: string;\n balanceError?: unknown;\n isERC721?: boolean;\n}\n\n/**\n * @type TokenRatesConfig\n *\n * Token rates controller configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property nativeCurrency - Current native currency selected to use base of rates\n * @property chainId - Current network chainId\n * @property tokens - List of tokens to track exchange rates for\n * @property threshold - Threshold to invalidate the supportedChains\n */\nexport interface TokenRatesConfig extends BaseConfig {\n interval: number;\n nativeCurrency: string;\n chainId: string;\n tokens: Token[];\n threshold: number;\n}\n\ninterface ContractExchangeRates {\n [address: string]: number | undefined;\n}\n\ninterface SupportedChainsCache {\n timestamp: number;\n data: CoinGeckoPlatform[] | null;\n}\n\ninterface SupportedVsCurrenciesCache {\n timestamp: number;\n data: string[];\n}\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property contractExchangeRates - Hash of token contract addresses to exchange rates\n * @property supportedChains - Cached chain data\n */\nexport interface TokenRatesState extends BaseState {\n contractExchangeRates: ContractExchangeRates;\n}\n\nconst CoinGeckoApi = {\n BASE_URL: 'https://api.coingecko.com/api/v3',\n getTokenPriceURL(chainSlug: string, query: string) {\n return `${this.BASE_URL}/simple/token_price/${chainSlug}?${query}`;\n },\n getPlatformsURL() {\n return `${this.BASE_URL}/asset_platforms`;\n },\n getSupportedVsCurrencies() {\n return `${this.BASE_URL}/simple/supported_vs_currencies`;\n },\n};\n\n/**\n * Finds the chain slug in the data array given a chainId.\n *\n * @param chainId - The current chain ID.\n * @param data - A list platforms supported by the CoinGecko API.\n * @returns The CoinGecko slug for the given chain ID, or `null` if the slug was not found.\n */\nfunction findChainSlug(\n chainId: string,\n data: CoinGeckoPlatform[] | null,\n): string | null {\n if (!data) {\n return null;\n }\n const chain =\n data.find(\n ({ chain_identifier }) =>\n chain_identifier !== null && String(chain_identifier) === chainId,\n ) ?? null;\n return chain?.id || null;\n}\n\n/**\n * Controller that passively polls on a set interval for token-to-fiat exchange rates\n * for tokens stored in the TokensController\n */\nexport class TokenRatesController extends BaseController<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n private tokenList: Token[] = [];\n\n private supportedChains: SupportedChainsCache = {\n timestamp: 0,\n data: null,\n };\n\n private supportedVsCurrencies: SupportedVsCurrenciesCache = {\n timestamp: 0,\n data: [],\n };\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenRatesController';\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.onTokensStateChange - Allows subscribing to token controller state changes.\n * @param options.onCurrencyRateStateChange - Allows subscribing to currency rate controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network state changes.\n * @param config - Initial options used to configure this controller.\n * @param state - Initial state to set on this controller.\n */\n constructor(\n {\n onTokensStateChange,\n onCurrencyRateStateChange,\n onNetworkStateChange,\n }: {\n onTokensStateChange: (\n listener: (tokensState: TokensState) => void,\n ) => void;\n onCurrencyRateStateChange: (\n listener: (currencyRateState: CurrencyRateState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n },\n config?: Partial<TokenRatesConfig>,\n state?: Partial<TokenRatesState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n disabled: true,\n interval: 3 * 60 * 1000,\n nativeCurrency: 'eth',\n chainId: '',\n tokens: [],\n threshold: 6 * 60 * 60 * 1000,\n };\n\n this.defaultState = {\n contractExchangeRates: {},\n };\n this.initialize();\n this.configure({ disabled: false }, false, false);\n onTokensStateChange(({ tokens, detectedTokens }) => {\n this.configure({ tokens: [...tokens, ...detectedTokens] });\n });\n\n onCurrencyRateStateChange((currencyRateState) => {\n this.configure({ nativeCurrency: currencyRateState.nativeCurrency });\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n const { chainId } = providerConfig;\n this.update({ contractExchangeRates: {} });\n this.configure({ chainId });\n });\n this.poll();\n }\n\n /**\n * Sets a new polling interval.\n *\n * @param interval - Polling interval used to fetch new token rates.\n */\n async poll(interval?: number): Promise<void> {\n interval && this.configure({ interval }, false, false);\n this.handle && clearTimeout(this.handle);\n await safelyExecute(() => this.updateExchangeRates());\n this.handle = setTimeout(() => {\n this.poll(this.config.interval);\n }, this.config.interval);\n }\n\n /**\n * Sets a new chainId.\n *\n * TODO: Replace this with a method.\n *\n * @param _chainId - The current chain ID.\n */\n set chainId(_chainId: string) {\n !this.disabled && safelyExecute(() => this.updateExchangeRates());\n }\n\n get chainId() {\n throw new Error('Property only used for setting');\n }\n\n /**\n * Sets a new token list to track prices.\n *\n * TODO: Replace this with a method.\n *\n * @param tokens - List of tokens to track exchange rates for.\n */\n set tokens(tokens: Token[]) {\n this.tokenList = tokens;\n !this.disabled && safelyExecute(() => this.updateExchangeRates());\n }\n\n get tokens() {\n throw new Error('Property only used for setting');\n }\n\n /**\n * Fetches a pairs of token address and native currency.\n *\n * @param chainSlug - Chain string identifier.\n * @param vsCurrency - Query according to tokens in tokenList and native currency.\n * @returns The exchange rates for the given pairs.\n */\n async fetchExchangeRate(\n chainSlug: string,\n vsCurrency: string,\n ): Promise<CoinGeckoResponse> {\n const tokenPairs = this.tokenList.map((token) => token.address).join(',');\n const query = `contract_addresses=${tokenPairs}&vs_currencies=${vsCurrency.toLowerCase()}`;\n return handleFetch(CoinGeckoApi.getTokenPriceURL(chainSlug, query));\n }\n\n /**\n * Checks if the current native currency is a supported vs currency to use\n * to query for token exchange rates.\n *\n * @param nativeCurrency - The native currency of the currently active network.\n * @returns A boolean indicating whether it's a supported vsCurrency.\n */\n private async checkIsSupportedVsCurrency(nativeCurrency: string) {\n const { threshold } = this.config;\n const { timestamp, data } = this.supportedVsCurrencies;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const currencies = await handleFetch(\n CoinGeckoApi.getSupportedVsCurrencies(),\n );\n this.supportedVsCurrencies = {\n data: currencies,\n timestamp: Date.now(),\n };\n return currencies.includes(nativeCurrency.toLowerCase());\n }\n\n return data.includes(nativeCurrency.toLowerCase());\n }\n\n /**\n * Gets current chain ID slug from cached supported platforms CoinGecko API response.\n * If cached supported platforms response is stale, fetches and updates it.\n *\n * @returns The CoinGecko slug for the current chain ID.\n */\n async getChainSlug(): Promise<string | null> {\n const { threshold, chainId } = this.config;\n const { data, timestamp } = this.supportedChains;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const platforms = await handleFetch(CoinGeckoApi.getPlatformsURL());\n this.supportedChains = {\n data: platforms,\n timestamp: Date.now(),\n };\n return findChainSlug(chainId, platforms);\n }\n\n return findChainSlug(chainId, data);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n if (this.tokenList.length === 0 || this.disabled) {\n return;\n }\n const slug = await this.getChainSlug();\n\n let newContractExchangeRates: ContractExchangeRates = {};\n if (!slug) {\n this.tokenList.forEach((token) => {\n const address = toChecksumHexAddress(token.address);\n newContractExchangeRates[address] = undefined;\n });\n } else {\n const { nativeCurrency } = this.config;\n newContractExchangeRates = await this.fetchAndMapExchangeRates(\n nativeCurrency,\n slug,\n );\n }\n this.update({ contractExchangeRates: newContractExchangeRates });\n }\n\n /**\n * Checks if the active network's native currency is supported by the coingecko API.\n * If supported, it fetches and maps contractExchange rates to a format to be consumed by the UI.\n * If not supported, it fetches contractExchange rates and maps them from token/fallback-currency\n * to token/nativeCurrency.\n *\n * @param nativeCurrency - The native currency of the currently active network.\n * @param slug - The unique slug used to id the chain by the coingecko api\n * should be used to query token exchange rates.\n * @returns An object with conversion rates for each token\n * related to the network's native currency.\n */\n async fetchAndMapExchangeRates(\n nativeCurrency: string,\n slug: string,\n ): Promise<ContractExchangeRates> {\n const contractExchangeRates: ContractExchangeRates = {};\n\n // check if native currency is supported as a vs_currency by the API\n const nativeCurrencySupported = await this.checkIsSupportedVsCurrency(\n nativeCurrency,\n );\n\n if (nativeCurrencySupported) {\n // If it is we can do a simple fetch against the CoinGecko API\n const prices = await this.fetchExchangeRate(slug, nativeCurrency);\n this.tokenList.forEach((token) => {\n const price = prices[token.address.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(token.address)] = price\n ? price[nativeCurrency.toLowerCase()]\n : 0;\n });\n } else {\n // if native currency is not supported we need to use a fallback vsCurrency, get the exchange rates\n // in token/fallback-currency format and convert them to expected token/nativeCurrency format.\n let tokenExchangeRates;\n let vsCurrencyToNativeCurrencyConversionRate = 0;\n try {\n [\n tokenExchangeRates,\n { conversionRate: vsCurrencyToNativeCurrencyConversionRate },\n ] = await Promise.all([\n this.fetchExchangeRate(slug, FALL_BACK_VS_CURRENCY),\n fetchNativeExchangeRate(nativeCurrency, FALL_BACK_VS_CURRENCY, false),\n ]);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return {};\n }\n throw error;\n }\n\n for (const [tokenAddress, conversion] of Object.entries(\n tokenExchangeRates,\n )) {\n const tokenToVsCurrencyConversionRate =\n conversion[FALL_BACK_VS_CURRENCY.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(tokenAddress)] =\n tokenToVsCurrencyConversionRate *\n vsCurrencyToNativeCurrencyConversionRate;\n }\n }\n\n return contractExchangeRates;\n }\n}\n\nexport default TokenRatesController;\n"]}
1
+ {"version":3,"file":"TokenRatesController.js","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n BaseConfig,\n BaseState,\n} from '@metamask/base-controller';\nimport {\n safelyExecute,\n handleFetch,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { NetworkState } from '@metamask/network-controller';\nimport { fetchExchangeRate as fetchNativeExchangeRate } from './crypto-compare';\nimport type { TokensState } from './TokensController';\nimport type { CurrencyRateState } from './CurrencyRateController';\n\n/**\n * @type CoinGeckoResponse\n *\n * CoinGecko API response representation\n */\nexport interface CoinGeckoResponse {\n [address: string]: {\n [currency: string]: number;\n };\n}\n/**\n * @type CoinGeckoPlatform\n *\n * CoinGecko supported platform API representation\n */\nexport interface CoinGeckoPlatform {\n id: string;\n chain_identifier: null | number;\n name: string;\n shortname: string;\n}\n\n/**\n * @type Token\n *\n * Token representation\n * @property address - Hex address of the token contract\n * @property decimals - Number of decimals the token uses\n * @property symbol - Symbol of the token\n * @property image - Image of the token, url or bit32 image\n */\nexport interface Token {\n address: string;\n decimals: number;\n symbol: string;\n aggregators?: string[];\n image?: string;\n balanceError?: unknown;\n isERC721?: boolean;\n}\n\n/**\n * @type TokenRatesConfig\n *\n * Token rates controller configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property nativeCurrency - Current native currency selected to use base of rates\n * @property chainId - Current network chainId\n * @property tokens - List of tokens to track exchange rates for\n * @property threshold - Threshold to invalidate the supportedChains\n */\nexport interface TokenRatesConfig extends BaseConfig {\n interval: number;\n nativeCurrency: string;\n chainId: string;\n tokens: Token[];\n threshold: number;\n}\n\ninterface ContractExchangeRates {\n [address: string]: number | undefined;\n}\n\ninterface SupportedChainsCache {\n timestamp: number;\n data: CoinGeckoPlatform[] | null;\n}\n\ninterface SupportedVsCurrenciesCache {\n timestamp: number;\n data: string[];\n}\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property contractExchangeRates - Hash of token contract addresses to exchange rates\n * @property supportedChains - Cached chain data\n */\nexport interface TokenRatesState extends BaseState {\n contractExchangeRates: ContractExchangeRates;\n}\n\nconst CoinGeckoApi = {\n BASE_URL: 'https://api.coingecko.com/api/v3',\n getTokenPriceURL(chainSlug: string, query: string) {\n return `${this.BASE_URL}/simple/token_price/${chainSlug}?${query}`;\n },\n getPlatformsURL() {\n return `${this.BASE_URL}/asset_platforms`;\n },\n getSupportedVsCurrencies() {\n return `${this.BASE_URL}/simple/supported_vs_currencies`;\n },\n};\n\n/**\n * Finds the chain slug in the data array given a chainId.\n *\n * @param chainId - The current chain ID.\n * @param data - A list platforms supported by the CoinGecko API.\n * @returns The CoinGecko slug for the given chain ID, or `null` if the slug was not found.\n */\nfunction findChainSlug(\n chainId: string,\n data: CoinGeckoPlatform[] | null,\n): string | null {\n if (!data) {\n return null;\n }\n const chain =\n data.find(\n ({ chain_identifier }) =>\n chain_identifier !== null && String(chain_identifier) === chainId,\n ) ?? null;\n return chain?.id || null;\n}\n\n/**\n * Controller that passively polls on a set interval for token-to-fiat exchange rates\n * for tokens stored in the TokensController\n */\nexport class TokenRatesController extends BaseController<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n private tokenList: Token[] = [];\n\n private supportedChains: SupportedChainsCache = {\n timestamp: 0,\n data: null,\n };\n\n private supportedVsCurrencies: SupportedVsCurrenciesCache = {\n timestamp: 0,\n data: [],\n };\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenRatesController';\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.onTokensStateChange - Allows subscribing to token controller state changes.\n * @param options.onCurrencyRateStateChange - Allows subscribing to currency rate controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network state changes.\n * @param config - Initial options used to configure this controller.\n * @param state - Initial state to set on this controller.\n */\n constructor(\n {\n onTokensStateChange,\n onCurrencyRateStateChange,\n onNetworkStateChange,\n }: {\n onTokensStateChange: (\n listener: (tokensState: TokensState) => void,\n ) => void;\n onCurrencyRateStateChange: (\n listener: (currencyRateState: CurrencyRateState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n },\n config?: Partial<TokenRatesConfig>,\n state?: Partial<TokenRatesState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n disabled: false,\n interval: 3 * 60 * 1000,\n nativeCurrency: 'eth',\n chainId: '',\n tokens: [],\n threshold: 6 * 60 * 60 * 1000,\n };\n\n this.defaultState = {\n contractExchangeRates: {},\n };\n this.initialize();\n if (config?.disabled) {\n this.configure({ disabled: true }, false, false);\n }\n\n onTokensStateChange(({ tokens, detectedTokens }) => {\n this.configure({ tokens: [...tokens, ...detectedTokens] });\n });\n\n onCurrencyRateStateChange((currencyRateState) => {\n this.configure({ nativeCurrency: currencyRateState.nativeCurrency });\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n const { chainId } = providerConfig;\n this.update({ contractExchangeRates: {} });\n this.configure({ chainId });\n });\n this.poll();\n }\n\n /**\n * Sets a new polling interval.\n *\n * @param interval - Polling interval used to fetch new token rates.\n */\n async poll(interval?: number): Promise<void> {\n interval && this.configure({ interval }, false, false);\n this.handle && clearTimeout(this.handle);\n await safelyExecute(() => this.updateExchangeRates());\n this.handle = setTimeout(() => {\n this.poll(this.config.interval);\n }, this.config.interval);\n }\n\n /**\n * Sets a new chainId.\n *\n * TODO: Replace this with a method.\n *\n * @param _chainId - The current chain ID.\n */\n set chainId(_chainId: string) {\n !this.disabled && safelyExecute(() => this.updateExchangeRates());\n }\n\n get chainId() {\n throw new Error('Property only used for setting');\n }\n\n /**\n * Sets a new token list to track prices.\n *\n * TODO: Replace this with a method.\n *\n * @param tokens - List of tokens to track exchange rates for.\n */\n set tokens(tokens: Token[]) {\n this.tokenList = tokens;\n !this.disabled && safelyExecute(() => this.updateExchangeRates());\n }\n\n get tokens() {\n throw new Error('Property only used for setting');\n }\n\n /**\n * Fetches a pairs of token address and native currency.\n *\n * @param chainSlug - Chain string identifier.\n * @param vsCurrency - Query according to tokens in tokenList and native currency.\n * @returns The exchange rates for the given pairs.\n */\n async fetchExchangeRate(\n chainSlug: string,\n vsCurrency: string,\n ): Promise<CoinGeckoResponse> {\n const tokenPairs = this.tokenList.map((token) => token.address).join(',');\n const query = `contract_addresses=${tokenPairs}&vs_currencies=${vsCurrency.toLowerCase()}`;\n return handleFetch(CoinGeckoApi.getTokenPriceURL(chainSlug, query));\n }\n\n /**\n * Checks if the current native currency is a supported vs currency to use\n * to query for token exchange rates.\n *\n * @param nativeCurrency - The native currency of the currently active network.\n * @returns A boolean indicating whether it's a supported vsCurrency.\n */\n private async checkIsSupportedVsCurrency(nativeCurrency: string) {\n const { threshold } = this.config;\n const { timestamp, data } = this.supportedVsCurrencies;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const currencies = await handleFetch(\n CoinGeckoApi.getSupportedVsCurrencies(),\n );\n this.supportedVsCurrencies = {\n data: currencies,\n timestamp: Date.now(),\n };\n return currencies.includes(nativeCurrency.toLowerCase());\n }\n\n return data.includes(nativeCurrency.toLowerCase());\n }\n\n /**\n * Gets current chain ID slug from cached supported platforms CoinGecko API response.\n * If cached supported platforms response is stale, fetches and updates it.\n *\n * @returns The CoinGecko slug for the current chain ID.\n */\n async getChainSlug(): Promise<string | null> {\n const { threshold, chainId } = this.config;\n const { data, timestamp } = this.supportedChains;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const platforms = await handleFetch(CoinGeckoApi.getPlatformsURL());\n this.supportedChains = {\n data: platforms,\n timestamp: Date.now(),\n };\n return findChainSlug(chainId, platforms);\n }\n\n return findChainSlug(chainId, data);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n if (this.tokenList.length === 0 || this.disabled) {\n return;\n }\n const slug = await this.getChainSlug();\n\n let newContractExchangeRates: ContractExchangeRates = {};\n if (!slug) {\n this.tokenList.forEach((token) => {\n const address = toChecksumHexAddress(token.address);\n newContractExchangeRates[address] = undefined;\n });\n } else {\n const { nativeCurrency } = this.config;\n newContractExchangeRates = await this.fetchAndMapExchangeRates(\n nativeCurrency,\n slug,\n );\n }\n this.update({ contractExchangeRates: newContractExchangeRates });\n }\n\n /**\n * Checks if the active network's native currency is supported by the coingecko API.\n * If supported, it fetches and maps contractExchange rates to a format to be consumed by the UI.\n * If not supported, it fetches contractExchange rates and maps them from token/fallback-currency\n * to token/nativeCurrency.\n *\n * @param nativeCurrency - The native currency of the currently active network.\n * @param slug - The unique slug used to id the chain by the coingecko api\n * should be used to query token exchange rates.\n * @returns An object with conversion rates for each token\n * related to the network's native currency.\n */\n async fetchAndMapExchangeRates(\n nativeCurrency: string,\n slug: string,\n ): Promise<ContractExchangeRates> {\n const contractExchangeRates: ContractExchangeRates = {};\n\n // check if native currency is supported as a vs_currency by the API\n const nativeCurrencySupported = await this.checkIsSupportedVsCurrency(\n nativeCurrency,\n );\n\n if (nativeCurrencySupported) {\n // If it is we can do a simple fetch against the CoinGecko API\n const prices = await this.fetchExchangeRate(slug, nativeCurrency);\n this.tokenList.forEach((token) => {\n const price = prices[token.address.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(token.address)] = price\n ? price[nativeCurrency.toLowerCase()]\n : 0;\n });\n } else {\n // if native currency is not supported we need to use a fallback vsCurrency, get the exchange rates\n // in token/fallback-currency format and convert them to expected token/nativeCurrency format.\n let tokenExchangeRates;\n let vsCurrencyToNativeCurrencyConversionRate = 0;\n try {\n [\n tokenExchangeRates,\n { conversionRate: vsCurrencyToNativeCurrencyConversionRate },\n ] = await Promise.all([\n this.fetchExchangeRate(slug, FALL_BACK_VS_CURRENCY),\n fetchNativeExchangeRate(nativeCurrency, FALL_BACK_VS_CURRENCY, false),\n ]);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return {};\n }\n throw error;\n }\n\n for (const [tokenAddress, conversion] of Object.entries(\n tokenExchangeRates,\n )) {\n const tokenToVsCurrencyConversionRate =\n conversion[FALL_BACK_VS_CURRENCY.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(tokenAddress)] =\n tokenToVsCurrencyConversionRate *\n vsCurrencyToNativeCurrencyConversionRate;\n }\n }\n\n return contractExchangeRates;\n }\n}\n\nexport default TokenRatesController;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/assets-controllers",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -65,6 +65,9 @@
65
65
  "typedoc-plugin-missing-exports": "^0.22.6",
66
66
  "typescript": "~4.6.3"
67
67
  },
68
+ "peerDependencies": {
69
+ "@metamask/network-controller": "^2.0.0"
70
+ },
68
71
  "engines": {
69
72
  "node": ">=14.0.0"
70
73
  },