@metamask-previews/assets-controllers 20.0.0-preview.3fbb6b41 → 23.1.0-preview.353ee83b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +103 -10
  2. package/dist/AccountTrackerController.d.ts +28 -7
  3. package/dist/AccountTrackerController.d.ts.map +1 -1
  4. package/dist/AccountTrackerController.js +104 -30
  5. package/dist/AccountTrackerController.js.map +1 -1
  6. package/dist/AssetsContractController.d.ts.map +1 -1
  7. package/dist/AssetsContractController.js +4 -0
  8. package/dist/AssetsContractController.js.map +1 -1
  9. package/dist/CurrencyRateController.d.ts +2 -2
  10. package/dist/CurrencyRateController.d.ts.map +1 -1
  11. package/dist/CurrencyRateController.js +1 -1
  12. package/dist/CurrencyRateController.js.map +1 -1
  13. package/dist/NftController.d.ts +75 -1
  14. package/dist/NftController.d.ts.map +1 -1
  15. package/dist/NftController.js +35 -14
  16. package/dist/NftController.js.map +1 -1
  17. package/dist/NftDetectionController.d.ts +7 -4
  18. package/dist/NftDetectionController.d.ts.map +1 -1
  19. package/dist/NftDetectionController.js +26 -14
  20. package/dist/NftDetectionController.js.map +1 -1
  21. package/dist/Standards/ERC20Standard.d.ts.map +1 -1
  22. package/dist/Standards/ERC20Standard.js +4 -0
  23. package/dist/Standards/ERC20Standard.js.map +1 -1
  24. package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts +11 -10
  25. package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts.map +1 -1
  26. package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js +106 -85
  27. package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js.map +1 -1
  28. package/dist/Standards/NftStandards/ERC721/ERC721Standard.d.ts.map +1 -1
  29. package/dist/Standards/NftStandards/ERC721/ERC721Standard.js +2 -0
  30. package/dist/Standards/NftStandards/ERC721/ERC721Standard.js.map +1 -1
  31. package/dist/Standards/standards-types.d.ts.map +1 -1
  32. package/dist/Standards/standards-types.js.map +1 -1
  33. package/dist/TokenDetectionController.d.ts +43 -56
  34. package/dist/TokenDetectionController.d.ts.map +1 -1
  35. package/dist/TokenDetectionController.js +132 -96
  36. package/dist/TokenDetectionController.js.map +1 -1
  37. package/dist/TokenListController.d.ts +6 -4
  38. package/dist/TokenListController.d.ts.map +1 -1
  39. package/dist/TokenListController.js +11 -10
  40. package/dist/TokenListController.js.map +1 -1
  41. package/dist/TokenRatesController.d.ts +6 -38
  42. package/dist/TokenRatesController.d.ts.map +1 -1
  43. package/dist/TokenRatesController.js +125 -93
  44. package/dist/TokenRatesController.js.map +1 -1
  45. package/dist/TokensController.d.ts +5 -6
  46. package/dist/TokensController.d.ts.map +1 -1
  47. package/dist/TokensController.js +81 -21
  48. package/dist/TokensController.js.map +1 -1
  49. package/dist/assetsUtil.d.ts +80 -9
  50. package/dist/assetsUtil.d.ts.map +1 -1
  51. package/dist/assetsUtil.js +177 -27
  52. package/dist/assetsUtil.js.map +1 -1
  53. package/dist/index.d.ts +4 -3
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +5 -3
  56. package/dist/index.js.map +1 -1
  57. package/dist/token-prices-service/abstract-token-prices-service.d.ts +15 -16
  58. package/dist/token-prices-service/abstract-token-prices-service.d.ts.map +1 -1
  59. package/dist/token-prices-service/abstract-token-prices-service.js.map +1 -1
  60. package/dist/token-prices-service/codefi-v2.d.ts +61 -3
  61. package/dist/token-prices-service/codefi-v2.d.ts.map +1 -1
  62. package/dist/token-prices-service/codefi-v2.js +86 -20
  63. package/dist/token-prices-service/codefi-v2.js.map +1 -1
  64. package/dist/token-prices-service/index.d.ts +1 -1
  65. package/dist/token-prices-service/index.js +2 -2
  66. package/dist/token-prices-service/index.js.map +1 -1
  67. package/package.json +15 -11
@@ -19,11 +19,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
19
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
20
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
21
21
  };
22
- var _TokenRatesController_instances, _TokenRatesController_pollState, _TokenRatesController_tokenPricesService, _TokenRatesController_updateTokenList, _TokenRatesController_stopPoll, _TokenRatesController_poll, _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency, _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency;
22
+ var _TokenRatesController_instances, _TokenRatesController_pollState, _TokenRatesController_tokenPricesService, _TokenRatesController_inProcessExchangeRateUpdates, _TokenRatesController_getTokenAddresses, _TokenRatesController_stopPoll, _TokenRatesController_poll, _TokenRatesController_fetchAndMapExchangeRates, _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency, _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency;
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
24
  exports.TokenRatesController = void 0;
25
25
  const controller_utils_1 = require("@metamask/controller-utils");
26
26
  const polling_controller_1 = require("@metamask/polling-controller");
27
+ const lodash_1 = require("lodash");
28
+ const assetsUtil_1 = require("./assetsUtil");
27
29
  const crypto_compare_1 = require("./crypto-compare");
28
30
  var PollState;
29
31
  (function (PollState) {
@@ -61,7 +63,7 @@ function getCurrencyConversionRate({ from, to, }) {
61
63
  * Controller that passively polls on a set interval for token-to-fiat exchange rates
62
64
  * for tokens stored in the TokensController
63
65
  */
64
- class TokenRatesController extends polling_controller_1.PollingControllerV1 {
66
+ class TokenRatesController extends polling_controller_1.StaticIntervalPollingControllerV1 {
65
67
  /**
66
68
  * Creates a TokenRatesController instance.
67
69
  *
@@ -82,9 +84,9 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
82
84
  constructor({ interval = 3 * 60 * 1000, threshold = 6 * 60 * 60 * 1000, getNetworkClientById, chainId: initialChainId, ticker: initialTicker, selectedAddress: initialSelectedAddress, onPreferencesStateChange, onTokensStateChange, onNetworkStateChange, tokenPricesService, }, config, state) {
83
85
  super(config, state);
84
86
  _TokenRatesController_instances.add(this);
85
- this.tokenList = [];
86
87
  _TokenRatesController_pollState.set(this, PollState.Inactive);
87
88
  _TokenRatesController_tokenPricesService.set(this, void 0);
89
+ _TokenRatesController_inProcessExchangeRateUpdates.set(this, {});
88
90
  /**
89
91
  * Name of this controller used during composition
90
92
  */
@@ -110,25 +112,21 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
110
112
  if (config === null || config === void 0 ? void 0 : config.disabled) {
111
113
  this.configure({ disabled: true }, false, false);
112
114
  }
113
- __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
114
115
  onPreferencesStateChange(({ selectedAddress }) => __awaiter(this, void 0, void 0, function* () {
115
116
  if (this.config.selectedAddress !== selectedAddress) {
116
117
  this.configure({ selectedAddress });
117
- __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
118
118
  if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
119
119
  yield this.updateExchangeRates();
120
120
  }
121
121
  }
122
122
  }));
123
123
  onTokensStateChange(({ allTokens, allDetectedTokens }) => __awaiter(this, void 0, void 0, function* () {
124
- // These two state properties are assumed to be immutable
125
- if (this.config.allTokens !== allTokens ||
126
- this.config.allDetectedTokens !== allDetectedTokens) {
127
- this.configure({ allTokens, allDetectedTokens });
128
- __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
129
- if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
130
- yield this.updateExchangeRates();
131
- }
124
+ const previousTokenAddresses = __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_getTokenAddresses).call(this, this.config.chainId);
125
+ this.configure({ allTokens, allDetectedTokens });
126
+ const newTokenAddresses = __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_getTokenAddresses).call(this, this.config.chainId);
127
+ if (!(0, lodash_1.isEqual)(previousTokenAddresses, newTokenAddresses) &&
128
+ __classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
129
+ yield this.updateExchangeRates();
132
130
  }
133
131
  }));
134
132
  onNetworkStateChange(({ providerConfig }) => __awaiter(this, void 0, void 0, function* () {
@@ -137,7 +135,6 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
137
135
  this.config.nativeCurrency !== ticker) {
138
136
  this.update({ contractExchangeRates: {} });
139
137
  this.configure({ chainId, nativeCurrency: ticker });
140
- __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
141
138
  if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
142
139
  yield this.updateExchangeRates();
143
140
  }
@@ -166,18 +163,10 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
166
163
  */
167
164
  updateExchangeRates() {
168
165
  return __awaiter(this, void 0, void 0, function* () {
169
- if (this.tokenList.length === 0 || this.disabled) {
170
- return;
171
- }
172
166
  const { chainId, nativeCurrency } = this.config;
173
- const tokenContractAddresses = this.tokenList.map((token) => token.address);
174
167
  yield this.updateExchangeRatesByChainId({
175
168
  chainId,
176
169
  nativeCurrency,
177
- tokenContractAddresses,
178
- });
179
- this.update({
180
- contractExchangeRates: this.state.contractExchangeRatesByChainId[chainId][nativeCurrency],
181
170
  });
182
171
  });
183
172
  }
@@ -187,92 +176,80 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
187
176
  * @param options - The options to fetch exchange rates.
188
177
  * @param options.chainId - The chain ID.
189
178
  * @param options.nativeCurrency - The ticker for the chain.
190
- * @param options.tokenContractAddresses - The addresses for the token contracts.
191
179
  */
192
- updateExchangeRatesByChainId({ chainId, nativeCurrency, tokenContractAddresses, }) {
180
+ updateExchangeRatesByChainId({ chainId, nativeCurrency, }) {
193
181
  var _a;
194
182
  return __awaiter(this, void 0, void 0, function* () {
195
- if (tokenContractAddresses.length === 0 || this.disabled) {
183
+ if (this.disabled) {
196
184
  return;
197
185
  }
198
- const newContractExchangeRates = yield this.fetchAndMapExchangeRates({
199
- tokenContractAddresses,
200
- chainId,
201
- nativeCurrency,
202
- });
203
- const existingContractExchangeRatesForChainId = (_a = this.state.contractExchangeRatesByChainId[chainId]) !== null && _a !== void 0 ? _a : {};
204
- this.update({
205
- contractExchangeRatesByChainId: Object.assign(Object.assign({}, this.state.contractExchangeRatesByChainId), { [chainId]: Object.assign(Object.assign({}, existingContractExchangeRatesForChainId), { [nativeCurrency]: Object.assign(Object.assign({}, existingContractExchangeRatesForChainId[nativeCurrency]), newContractExchangeRates) }) }),
206
- });
207
- });
208
- }
209
- /**
210
- * Uses the token prices service to retrieve exchange rates for tokens in a
211
- * particular currency.
212
- *
213
- * If the price API does not support the given chain ID, returns an empty
214
- * object.
215
- *
216
- * If the price API does not support the given currency, retrieves exchange
217
- * rates in a known currency instead, then converts those rates using the
218
- * exchange rate between the known currency and desired currency.
219
- *
220
- * @param args - The arguments to this function.
221
- * @param args.tokenContractAddresses - Contract addresses for tokens.
222
- * @param args.chainId - The EIP-155 ID of the chain where the tokens live.
223
- * @param args.nativeCurrency - The native currency in which to request
224
- * exchange rates.
225
- * @returns A map from token contract address to its exchange rate in the
226
- * native currency, or an empty map if no exchange rates can be obtained for
227
- * the chain ID.
228
- */
229
- fetchAndMapExchangeRates({ tokenContractAddresses, chainId, nativeCurrency, }) {
230
- return __awaiter(this, void 0, void 0, function* () {
231
- if (!__classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").validateChainIdSupported(chainId)) {
232
- return tokenContractAddresses.reduce((obj, tokenContractAddress) => {
233
- return Object.assign(Object.assign({}, obj), { [tokenContractAddress]: undefined });
234
- }, {});
186
+ const tokenAddresses = __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_getTokenAddresses).call(this, chainId);
187
+ if (tokenAddresses.length === 0) {
188
+ return;
189
+ }
190
+ const updateKey = `${chainId}:${nativeCurrency}`;
191
+ if (updateKey in __classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")) {
192
+ // This prevents redundant updates
193
+ // This promise is resolved after the in-progress update has finished,
194
+ // and state has been updated.
195
+ yield __classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")[updateKey];
196
+ return;
235
197
  }
236
- if (__classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").validateCurrencySupported(nativeCurrency)) {
237
- return yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency).call(this, {
238
- tokenContractAddresses,
198
+ const { promise: inProgressUpdate, resolve: updateSucceeded, reject: updateFailed, } = createDeferredPromise({ suppressUnhandledRejection: true });
199
+ __classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")[updateKey] = inProgressUpdate;
200
+ try {
201
+ const newContractExchangeRates = yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRates).call(this, {
202
+ tokenAddresses,
239
203
  chainId,
240
204
  nativeCurrency,
241
205
  });
206
+ const existingContractExchangeRates = this.state.contractExchangeRates;
207
+ const updatedContractExchangeRates = chainId === this.config.chainId &&
208
+ nativeCurrency === this.config.nativeCurrency
209
+ ? newContractExchangeRates
210
+ : existingContractExchangeRates;
211
+ const existingContractExchangeRatesForChainId = (_a = this.state.contractExchangeRatesByChainId[chainId]) !== null && _a !== void 0 ? _a : {};
212
+ const updatedContractExchangeRatesForChainId = Object.assign(Object.assign({}, this.state.contractExchangeRatesByChainId), { [chainId]: Object.assign(Object.assign({}, existingContractExchangeRatesForChainId), { [nativeCurrency]: Object.assign(Object.assign({}, existingContractExchangeRatesForChainId[nativeCurrency]), newContractExchangeRates) }) });
213
+ this.update({
214
+ contractExchangeRates: updatedContractExchangeRates,
215
+ contractExchangeRatesByChainId: updatedContractExchangeRatesForChainId,
216
+ });
217
+ updateSucceeded();
218
+ }
219
+ catch (error) {
220
+ updateFailed(error);
221
+ throw error;
222
+ }
223
+ finally {
224
+ delete __classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")[updateKey];
242
225
  }
243
- return yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency).call(this, {
244
- tokenContractAddresses,
245
- nativeCurrency,
246
- });
247
226
  });
248
227
  }
249
228
  /**
250
- * Updates token rates for the given networkClientId and contract addresses
229
+ * Updates token rates for the given networkClientId
251
230
  *
252
231
  * @param networkClientId - The network client ID used to get a ticker value.
253
- * @param options - The polling options.
254
- * @param options.tokenAddresses - The addresses for the token contracts.
255
232
  * @returns The controller state.
256
233
  */
257
- _executePoll(networkClientId, options) {
234
+ _executePoll(networkClientId) {
258
235
  return __awaiter(this, void 0, void 0, function* () {
259
236
  const networkClient = this.getNetworkClientById(networkClientId);
260
237
  yield this.updateExchangeRatesByChainId({
261
238
  chainId: networkClient.configuration.chainId,
262
239
  nativeCurrency: networkClient.configuration.ticker,
263
- tokenContractAddresses: options.tokenAddresses,
264
240
  });
265
241
  });
266
242
  }
267
243
  }
268
244
  exports.TokenRatesController = TokenRatesController;
269
- _TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPricesService = new WeakMap(), _TokenRatesController_instances = new WeakSet(), _TokenRatesController_updateTokenList = function _TokenRatesController_updateTokenList() {
245
+ _TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPricesService = new WeakMap(), _TokenRatesController_inProcessExchangeRateUpdates = new WeakMap(), _TokenRatesController_instances = new WeakSet(), _TokenRatesController_getTokenAddresses = function _TokenRatesController_getTokenAddresses(chainId) {
270
246
  var _a, _b;
271
247
  const { allTokens, allDetectedTokens } = this.config;
272
- const tokens = ((_a = allTokens[this.config.chainId]) === null || _a === void 0 ? void 0 : _a[this.config.selectedAddress]) || [];
273
- const detectedTokens = ((_b = allDetectedTokens[this.config.chainId]) === null || _b === void 0 ? void 0 : _b[this.config.selectedAddress]) ||
274
- [];
275
- this.tokenList = [...tokens, ...detectedTokens];
248
+ const tokens = ((_a = allTokens[chainId]) === null || _a === void 0 ? void 0 : _a[this.config.selectedAddress]) || [];
249
+ const detectedTokens = ((_b = allDetectedTokens[chainId]) === null || _b === void 0 ? void 0 : _b[this.config.selectedAddress]) || [];
250
+ return [
251
+ ...new Set([...tokens, ...detectedTokens].map((token) => (0, controller_utils_1.toHex)((0, controller_utils_1.toChecksumHexAddress)(token.address)))),
252
+ ].sort();
276
253
  }, _TokenRatesController_stopPoll = function _TokenRatesController_stopPoll() {
277
254
  if (this.handle) {
278
255
  clearTimeout(this.handle);
@@ -286,24 +263,51 @@ _TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPric
286
263
  __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_poll).call(this);
287
264
  }, this.config.interval);
288
265
  });
289
- }, _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency = function _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency({ tokenContractAddresses, chainId, nativeCurrency, }) {
266
+ }, _TokenRatesController_fetchAndMapExchangeRates = function _TokenRatesController_fetchAndMapExchangeRates({ tokenAddresses, chainId, nativeCurrency, }) {
267
+ return __awaiter(this, void 0, void 0, function* () {
268
+ if (!__classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").validateChainIdSupported(chainId)) {
269
+ return tokenAddresses.reduce((obj, tokenAddress) => {
270
+ return Object.assign(Object.assign({}, obj), { [tokenAddress]: undefined });
271
+ }, {});
272
+ }
273
+ if (__classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").validateCurrencySupported(nativeCurrency)) {
274
+ return yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency).call(this, {
275
+ tokenAddresses,
276
+ chainId,
277
+ nativeCurrency,
278
+ });
279
+ }
280
+ return yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency).call(this, {
281
+ tokenAddresses,
282
+ nativeCurrency,
283
+ });
284
+ });
285
+ }, _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency = function _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency({ tokenAddresses, chainId, nativeCurrency, }) {
290
286
  return __awaiter(this, void 0, void 0, function* () {
291
- const tokenPricesByTokenContractAddress = yield __classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").fetchTokenPrices({
292
- tokenContractAddresses,
293
- chainId,
294
- currency: nativeCurrency,
287
+ const tokenPricesByTokenAddress = yield (0, assetsUtil_1.reduceInBatchesSerially)({
288
+ values: tokenAddresses,
289
+ batchSize: assetsUtil_1.TOKEN_PRICES_BATCH_SIZE,
290
+ eachBatch: (allTokenPricesByTokenAddress, batch) => __awaiter(this, void 0, void 0, function* () {
291
+ const tokenPricesByTokenAddressForBatch = yield __classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").fetchTokenPrices({
292
+ tokenAddresses: batch,
293
+ chainId,
294
+ currency: nativeCurrency,
295
+ });
296
+ return Object.assign(Object.assign({}, allTokenPricesByTokenAddress), tokenPricesByTokenAddressForBatch);
297
+ }),
298
+ initialResult: {},
295
299
  });
296
- return Object.entries(tokenPricesByTokenContractAddress).reduce((obj, [tokenContractAddress, tokenPrice]) => {
297
- return Object.assign(Object.assign({}, obj), { [(0, controller_utils_1.toChecksumHexAddress)(tokenContractAddress)]: tokenPrice.value });
300
+ return Object.entries(tokenPricesByTokenAddress).reduce((obj, [tokenAddress, tokenPrice]) => {
301
+ return Object.assign(Object.assign({}, obj), { [tokenAddress]: tokenPrice === null || tokenPrice === void 0 ? void 0 : tokenPrice.value });
298
302
  }, {});
299
303
  });
300
- }, _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency = function _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency({ tokenContractAddresses, nativeCurrency, }) {
304
+ }, _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency = function _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency({ tokenAddresses, nativeCurrency, }) {
301
305
  return __awaiter(this, void 0, void 0, function* () {
302
- const [tokenPricesByTokenContractAddress, fallbackCurrencyToNativeCurrencyConversionRate,] = yield Promise.all([
303
- __classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").fetchTokenPrices({
304
- tokenContractAddresses,
305
- currency: controller_utils_1.FALL_BACK_VS_CURRENCY,
306
+ const [contractExchangeRates, fallbackCurrencyToNativeCurrencyConversionRate,] = yield Promise.all([
307
+ __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency).call(this, {
308
+ tokenAddresses,
306
309
  chainId: this.config.chainId,
310
+ nativeCurrency: controller_utils_1.FALL_BACK_VS_CURRENCY,
307
311
  }),
308
312
  getCurrencyConversionRate({
309
313
  from: controller_utils_1.FALL_BACK_VS_CURRENCY,
@@ -313,10 +317,38 @@ _TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPric
313
317
  if (fallbackCurrencyToNativeCurrencyConversionRate === null) {
314
318
  return {};
315
319
  }
316
- return Object.entries(tokenPricesByTokenContractAddress).reduce((obj, [tokenContractAddress, tokenPrice]) => {
317
- return Object.assign(Object.assign({}, obj), { [(0, controller_utils_1.toChecksumHexAddress)(tokenContractAddress)]: tokenPrice.value * fallbackCurrencyToNativeCurrencyConversionRate });
320
+ return Object.entries(contractExchangeRates).reduce((obj, [tokenAddress, tokenValue]) => {
321
+ return Object.assign(Object.assign({}, obj), { [tokenAddress]: tokenValue
322
+ ? tokenValue * fallbackCurrencyToNativeCurrencyConversionRate
323
+ : undefined });
318
324
  }, {});
319
325
  });
320
326
  };
327
+ /**
328
+ * Create a defered Promise.
329
+ *
330
+ * TODO: Migrate this to utils
331
+ *
332
+ * @param args - The arguments.
333
+ * @param args.suppressUnhandledRejection - This option adds an empty error handler
334
+ * to the Promise to suppress the UnhandledPromiseRejection error. This can be
335
+ * useful if the deferred Promise is sometimes intentionally not used.
336
+ * @returns A deferred Promise.
337
+ */
338
+ function createDeferredPromise({ suppressUnhandledRejection = false, }) {
339
+ let resolve;
340
+ let reject;
341
+ const promise = new Promise((innerResolve, innerReject) => {
342
+ resolve = innerResolve;
343
+ reject = innerReject;
344
+ });
345
+ if (suppressUnhandledRejection) {
346
+ promise.catch((_error) => {
347
+ // This handler is used to suppress the UnhandledPromiseRejection error
348
+ });
349
+ }
350
+ // @ts-expect-error We know that these are assigned, but TypeScript doesn't
351
+ return { promise, resolve, reject };
352
+ }
321
353
  exports.default = TokenRatesController;
322
354
  //# sourceMappingURL=TokenRatesController.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TokenRatesController.js","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseConfig, BaseState } from '@metamask/base-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type {\n NetworkClientId,\n NetworkController,\n NetworkState,\n} from '@metamask/network-controller';\nimport { PollingControllerV1 } from '@metamask/polling-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport { fetchExchangeRate as fetchNativeCurrencyExchangeRate } from './crypto-compare';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport type { TokensState } from './TokensController';\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 */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\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 name?: string;\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 */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesConfig extends BaseConfig {\n interval: number;\n nativeCurrency: string;\n chainId: Hex;\n selectedAddress: string;\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n threshold: number;\n}\n\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ninterface ContractExchangeRates {\n [address: string]: number | undefined;\n}\n\nenum PollState {\n Active = 'Active',\n Inactive = 'Inactive',\n}\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property contractExchangeRates - Hash of token contract addresses to exchange rates (single globally selected chain, will be deprecated soon)\n * @property contractExchangeRatesByChainId - Hash of token contract addresses to exchange rates keyed by chain ID and native currency (ticker)\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesState extends BaseState {\n contractExchangeRates: ContractExchangeRates;\n contractExchangeRatesByChainId: Record<\n Hex,\n Record<string, ContractExchangeRates>\n >;\n}\n\n/**\n * Uses the CryptoCompare API to fetch the exchange rate between one currency\n * and another, i.e., the multiplier to apply the amount of one currency in\n * order to convert it to another.\n *\n * @param args - The arguments to this function.\n * @param args.from - The currency to convert from.\n * @param args.to - The currency to convert to.\n * @returns The exchange rate between `fromCurrency` to `toCurrency` if one\n * exists, or null if one does not.\n */\nasync function getCurrencyConversionRate({\n from,\n to,\n}: {\n from: string;\n to: string;\n}) {\n const includeUSDRate = false;\n try {\n const result = await fetchNativeCurrencyExchangeRate(\n to,\n from,\n includeUSDRate,\n );\n return result.conversionRate;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return null;\n }\n throw error;\n }\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 PollingControllerV1<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n private tokenList: Token[] = [];\n\n #pollState = PollState.Inactive;\n\n #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenRatesController';\n\n private readonly getNetworkClientById: NetworkController['getNetworkClientById'];\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.interval - The polling interval in ms\n * @param options.threshold - The duration in ms before metadata fetched from CoinGecko is considered stale\n * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.\n * @param options.chainId - The chain ID of the current network.\n * @param options.ticker - The ticker for the current network.\n * @param options.selectedAddress - The current selected address.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onTokensStateChange - Allows subscribing to token controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network state changes.\n * @param options.tokenPricesService - An object in charge of retrieving token prices.\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 interval = 3 * 60 * 1000,\n threshold = 6 * 60 * 60 * 1000,\n getNetworkClientById,\n chainId: initialChainId,\n ticker: initialTicker,\n selectedAddress: initialSelectedAddress,\n onPreferencesStateChange,\n onTokensStateChange,\n onNetworkStateChange,\n tokenPricesService,\n }: {\n interval?: number;\n threshold?: number;\n getNetworkClientById: NetworkController['getNetworkClientById'];\n chainId: Hex;\n ticker: string;\n selectedAddress: string;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onTokensStateChange: (\n listener: (tokensState: TokensState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n tokenPricesService: AbstractTokenPricesService;\n },\n config?: Partial<TokenRatesConfig>,\n state?: Partial<TokenRatesState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n interval,\n threshold,\n disabled: false,\n nativeCurrency: initialTicker,\n chainId: initialChainId,\n selectedAddress: initialSelectedAddress,\n allTokens: {}, // TODO: initialize these correctly, maybe as part of BaseControllerV2 migration\n allDetectedTokens: {},\n };\n\n this.defaultState = {\n contractExchangeRates: {},\n contractExchangeRatesByChainId: {},\n };\n this.initialize();\n this.setIntervalLength(interval);\n this.getNetworkClientById = getNetworkClientById;\n this.#tokenPricesService = tokenPricesService;\n\n if (config?.disabled) {\n this.configure({ disabled: true }, false, false);\n }\n this.#updateTokenList();\n\n onPreferencesStateChange(async ({ selectedAddress }) => {\n if (this.config.selectedAddress !== selectedAddress) {\n this.configure({ selectedAddress });\n this.#updateTokenList();\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n\n onTokensStateChange(async ({ allTokens, allDetectedTokens }) => {\n // These two state properties are assumed to be immutable\n if (\n this.config.allTokens !== allTokens ||\n this.config.allDetectedTokens !== allDetectedTokens\n ) {\n this.configure({ allTokens, allDetectedTokens });\n this.#updateTokenList();\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n\n onNetworkStateChange(async ({ providerConfig }) => {\n const { chainId, ticker } = providerConfig;\n if (\n this.config.chainId !== chainId ||\n this.config.nativeCurrency !== ticker\n ) {\n this.update({ contractExchangeRates: {} });\n this.configure({ chainId, nativeCurrency: ticker });\n this.#updateTokenList();\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n }\n\n #updateTokenList() {\n const { allTokens, allDetectedTokens } = this.config;\n const tokens =\n allTokens[this.config.chainId]?.[this.config.selectedAddress] || [];\n const detectedTokens =\n allDetectedTokens[this.config.chainId]?.[this.config.selectedAddress] ||\n [];\n this.tokenList = [...tokens, ...detectedTokens];\n }\n\n /**\n * Start (or restart) polling.\n */\n async start() {\n this.#stopPoll();\n this.#pollState = PollState.Active;\n await this.#poll();\n }\n\n /**\n * Stop polling.\n */\n stop() {\n this.#stopPoll();\n this.#pollState = PollState.Inactive;\n }\n\n /**\n * Clear the active polling timer, if present.\n */\n #stopPoll() {\n if (this.handle) {\n clearTimeout(this.handle);\n }\n }\n\n /**\n * Poll for exchange rate updates.\n */\n async #poll() {\n await safelyExecute(() => this.updateExchangeRates());\n\n // Poll using recursive `setTimeout` instead of `setInterval` so that\n // requests don't stack if they take longer than the polling interval\n this.handle = setTimeout(() => {\n this.#poll();\n }, this.config.interval);\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\n const { chainId, nativeCurrency } = this.config;\n const tokenContractAddresses = this.tokenList.map(\n (token) => token.address,\n ) as Hex[];\n await this.updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n tokenContractAddresses,\n });\n\n this.update({\n contractExchangeRates:\n this.state.contractExchangeRatesByChainId[chainId][nativeCurrency],\n });\n }\n\n /**\n * Updates exchange rates for all tokens.\n *\n * @param options - The options to fetch exchange rates.\n * @param options.chainId - The chain ID.\n * @param options.nativeCurrency - The ticker for the chain.\n * @param options.tokenContractAddresses - The addresses for the token contracts.\n */\n async updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n tokenContractAddresses,\n }: {\n chainId: Hex;\n nativeCurrency: string;\n tokenContractAddresses: Hex[];\n }) {\n if (tokenContractAddresses.length === 0 || this.disabled) {\n return;\n }\n\n const newContractExchangeRates = await this.fetchAndMapExchangeRates({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n });\n\n const existingContractExchangeRatesForChainId =\n this.state.contractExchangeRatesByChainId[chainId] ?? {};\n\n this.update({\n contractExchangeRatesByChainId: {\n ...this.state.contractExchangeRatesByChainId,\n [chainId]: {\n ...existingContractExchangeRatesForChainId,\n [nativeCurrency]: {\n ...existingContractExchangeRatesForChainId[nativeCurrency],\n ...newContractExchangeRates,\n },\n },\n },\n });\n }\n\n /**\n * Uses the token prices service to retrieve exchange rates for tokens in a\n * particular currency.\n *\n * If the price API does not support the given chain ID, returns an empty\n * object.\n *\n * If the price API does not support the given currency, retrieves exchange\n * rates in a known currency instead, then converts those rates using the\n * exchange rate between the known currency and desired currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenContractAddresses - Contract addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * exchange rates.\n * @returns A map from token contract address to its exchange rate in the\n * native currency, or an empty map if no exchange rates can be obtained for\n * the chain ID.\n */\n async fetchAndMapExchangeRates({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenContractAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n if (!this.#tokenPricesService.validateChainIdSupported(chainId)) {\n return tokenContractAddresses.reduce((obj, tokenContractAddress) => {\n return {\n ...obj,\n [tokenContractAddress]: undefined,\n };\n }, {});\n }\n\n if (this.#tokenPricesService.validateCurrencySupported(nativeCurrency)) {\n return await this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n });\n }\n\n return await this.#fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenContractAddresses,\n nativeCurrency,\n });\n }\n\n /**\n * Updates token rates for the given networkClientId and contract addresses\n *\n * @param networkClientId - The network client ID used to get a ticker value.\n * @param options - The polling options.\n * @param options.tokenAddresses - The addresses for the token contracts.\n * @returns The controller state.\n */\n async _executePoll(\n networkClientId: NetworkClientId,\n options: { tokenAddresses: Hex[] },\n ): Promise<void> {\n const networkClient = this.getNetworkClientById(networkClientId);\n await this.updateExchangeRatesByChainId({\n chainId: networkClient.configuration.chainId,\n nativeCurrency: networkClient.configuration.ticker,\n tokenContractAddresses: options.tokenAddresses,\n });\n }\n\n /**\n * Retrieves prices in the given currency for the given tokens on the given\n * chain. Ensures that token addresses are checksum addresses.\n *\n * @param args - The arguments to this function.\n * @param args.tokenContractAddresses - Contract addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenContractAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const tokenPricesByTokenContractAddress =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenContractAddresses,\n chainId,\n currency: nativeCurrency,\n });\n\n return Object.entries(tokenPricesByTokenContractAddress).reduce(\n (obj, [tokenContractAddress, tokenPrice]) => {\n return {\n ...obj,\n [toChecksumHexAddress(tokenContractAddress)]: tokenPrice.value,\n };\n },\n {},\n );\n }\n\n /**\n * If the price API does not support a given native currency, then we need to\n * convert it to a fallback currency and feed that currency into the price\n * API, then convert the prices to our desired native currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenContractAddresses - The contract addresses for the tokens you\n * want to retrieve prices for.\n * @param args.nativeCurrency - The currency you want the prices to be in.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenContractAddresses,\n nativeCurrency,\n }: {\n tokenContractAddresses: Hex[];\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const [\n tokenPricesByTokenContractAddress,\n fallbackCurrencyToNativeCurrencyConversionRate,\n ] = await Promise.all([\n this.#tokenPricesService.fetchTokenPrices({\n tokenContractAddresses,\n currency: FALL_BACK_VS_CURRENCY,\n chainId: this.config.chainId,\n }),\n getCurrencyConversionRate({\n from: FALL_BACK_VS_CURRENCY,\n to: nativeCurrency,\n }),\n ]);\n\n if (fallbackCurrencyToNativeCurrencyConversionRate === null) {\n return {};\n }\n\n return Object.entries(tokenPricesByTokenContractAddress).reduce(\n (obj, [tokenContractAddress, tokenPrice]) => {\n return {\n ...obj,\n [toChecksumHexAddress(tokenContractAddress)]:\n tokenPrice.value * fallbackCurrencyToNativeCurrencyConversionRate,\n };\n },\n {},\n );\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 type { BaseConfig, BaseState } from '@metamask/base-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n toHex,\n} from '@metamask/controller-utils';\nimport type {\n NetworkClientId,\n NetworkController,\n NetworkState,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingControllerV1 } from '@metamask/polling-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { isEqual } from 'lodash';\n\nimport { reduceInBatchesSerially, TOKEN_PRICES_BATCH_SIZE } from './assetsUtil';\nimport { fetchExchangeRate as fetchNativeCurrencyExchangeRate } from './crypto-compare';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport type { TokensState } from './TokensController';\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 */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\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 name?: string;\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 */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesConfig extends BaseConfig {\n interval: number;\n nativeCurrency: string;\n chainId: Hex;\n selectedAddress: string;\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n threshold: number;\n}\n\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface ContractExchangeRates {\n [address: string]: number | undefined;\n}\n\nenum PollState {\n Active = 'Active',\n Inactive = 'Inactive',\n}\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property contractExchangeRates - Hash of token contract addresses to exchange rates (single globally selected chain, will be deprecated soon)\n * @property contractExchangeRatesByChainId - Hash of token contract addresses to exchange rates keyed by chain ID and native currency (ticker)\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesState extends BaseState {\n contractExchangeRates: ContractExchangeRates;\n contractExchangeRatesByChainId: Record<\n Hex,\n Record<string, ContractExchangeRates>\n >;\n}\n\n/**\n * Uses the CryptoCompare API to fetch the exchange rate between one currency\n * and another, i.e., the multiplier to apply the amount of one currency in\n * order to convert it to another.\n *\n * @param args - The arguments to this function.\n * @param args.from - The currency to convert from.\n * @param args.to - The currency to convert to.\n * @returns The exchange rate between `fromCurrency` to `toCurrency` if one\n * exists, or null if one does not.\n */\nasync function getCurrencyConversionRate({\n from,\n to,\n}: {\n from: string;\n to: string;\n}) {\n const includeUSDRate = false;\n try {\n const result = await fetchNativeCurrencyExchangeRate(\n to,\n from,\n includeUSDRate,\n );\n return result.conversionRate;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return null;\n }\n throw error;\n }\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 StaticIntervalPollingControllerV1<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n #pollState = PollState.Inactive;\n\n #tokenPricesService: AbstractTokenPricesService;\n\n #inProcessExchangeRateUpdates: Record<`${Hex}:${string}`, Promise<void>> = {};\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenRatesController';\n\n private readonly getNetworkClientById: NetworkController['getNetworkClientById'];\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.interval - The polling interval in ms\n * @param options.threshold - The duration in ms before metadata fetched from CoinGecko is considered stale\n * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.\n * @param options.chainId - The chain ID of the current network.\n * @param options.ticker - The ticker for the current network.\n * @param options.selectedAddress - The current selected address.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onTokensStateChange - Allows subscribing to token controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network state changes.\n * @param options.tokenPricesService - An object in charge of retrieving token prices.\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 interval = 3 * 60 * 1000,\n threshold = 6 * 60 * 60 * 1000,\n getNetworkClientById,\n chainId: initialChainId,\n ticker: initialTicker,\n selectedAddress: initialSelectedAddress,\n onPreferencesStateChange,\n onTokensStateChange,\n onNetworkStateChange,\n tokenPricesService,\n }: {\n interval?: number;\n threshold?: number;\n getNetworkClientById: NetworkController['getNetworkClientById'];\n chainId: Hex;\n ticker: string;\n selectedAddress: string;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onTokensStateChange: (\n listener: (tokensState: TokensState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n tokenPricesService: AbstractTokenPricesService;\n },\n config?: Partial<TokenRatesConfig>,\n state?: Partial<TokenRatesState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n interval,\n threshold,\n disabled: false,\n nativeCurrency: initialTicker,\n chainId: initialChainId,\n selectedAddress: initialSelectedAddress,\n allTokens: {}, // TODO: initialize these correctly, maybe as part of BaseControllerV2 migration\n allDetectedTokens: {},\n };\n\n this.defaultState = {\n contractExchangeRates: {},\n contractExchangeRatesByChainId: {},\n };\n this.initialize();\n this.setIntervalLength(interval);\n this.getNetworkClientById = getNetworkClientById;\n this.#tokenPricesService = tokenPricesService;\n\n if (config?.disabled) {\n this.configure({ disabled: true }, false, false);\n }\n\n onPreferencesStateChange(async ({ selectedAddress }) => {\n if (this.config.selectedAddress !== selectedAddress) {\n this.configure({ selectedAddress });\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n\n onTokensStateChange(async ({ allTokens, allDetectedTokens }) => {\n const previousTokenAddresses = this.#getTokenAddresses(\n this.config.chainId,\n );\n this.configure({ allTokens, allDetectedTokens });\n const newTokenAddresses = this.#getTokenAddresses(this.config.chainId);\n if (\n !isEqual(previousTokenAddresses, newTokenAddresses) &&\n this.#pollState === PollState.Active\n ) {\n await this.updateExchangeRates();\n }\n });\n\n onNetworkStateChange(async ({ providerConfig }) => {\n const { chainId, ticker } = providerConfig;\n if (\n this.config.chainId !== chainId ||\n this.config.nativeCurrency !== ticker\n ) {\n this.update({ contractExchangeRates: {} });\n this.configure({ chainId, nativeCurrency: ticker });\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n }\n\n /**\n * Get the user's tokens for the given chain.\n *\n * @param chainId - The chain ID.\n * @returns The list of tokens addresses for the current chain\n */\n #getTokenAddresses(chainId: Hex): Hex[] {\n const { allTokens, allDetectedTokens } = this.config;\n const tokens = allTokens[chainId]?.[this.config.selectedAddress] || [];\n const detectedTokens =\n allDetectedTokens[chainId]?.[this.config.selectedAddress] || [];\n\n return [\n ...new Set(\n [...tokens, ...detectedTokens].map((token) =>\n toHex(toChecksumHexAddress(token.address)),\n ),\n ),\n ].sort();\n }\n\n /**\n * Start (or restart) polling.\n */\n async start() {\n this.#stopPoll();\n this.#pollState = PollState.Active;\n await this.#poll();\n }\n\n /**\n * Stop polling.\n */\n stop() {\n this.#stopPoll();\n this.#pollState = PollState.Inactive;\n }\n\n /**\n * Clear the active polling timer, if present.\n */\n #stopPoll() {\n if (this.handle) {\n clearTimeout(this.handle);\n }\n }\n\n /**\n * Poll for exchange rate updates.\n */\n async #poll() {\n await safelyExecute(() => this.updateExchangeRates());\n\n // Poll using recursive `setTimeout` instead of `setInterval` so that\n // requests don't stack if they take longer than the polling interval\n this.handle = setTimeout(() => {\n this.#poll();\n }, this.config.interval);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n const { chainId, nativeCurrency } = this.config;\n await this.updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n });\n }\n\n /**\n * Updates exchange rates for all tokens.\n *\n * @param options - The options to fetch exchange rates.\n * @param options.chainId - The chain ID.\n * @param options.nativeCurrency - The ticker for the chain.\n */\n async updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n }: {\n chainId: Hex;\n nativeCurrency: string;\n }) {\n if (this.disabled) {\n return;\n }\n\n const tokenAddresses = this.#getTokenAddresses(chainId);\n if (tokenAddresses.length === 0) {\n return;\n }\n\n const updateKey: `${Hex}:${string}` = `${chainId}:${nativeCurrency}`;\n if (updateKey in this.#inProcessExchangeRateUpdates) {\n // This prevents redundant updates\n // This promise is resolved after the in-progress update has finished,\n // and state has been updated.\n await this.#inProcessExchangeRateUpdates[updateKey];\n return;\n }\n\n const {\n promise: inProgressUpdate,\n resolve: updateSucceeded,\n reject: updateFailed,\n } = createDeferredPromise({ suppressUnhandledRejection: true });\n this.#inProcessExchangeRateUpdates[updateKey] = inProgressUpdate;\n\n try {\n const newContractExchangeRates = await this.#fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n\n const existingContractExchangeRates = this.state.contractExchangeRates;\n const updatedContractExchangeRates =\n chainId === this.config.chainId &&\n nativeCurrency === this.config.nativeCurrency\n ? newContractExchangeRates\n : existingContractExchangeRates;\n\n const existingContractExchangeRatesForChainId =\n this.state.contractExchangeRatesByChainId[chainId] ?? {};\n const updatedContractExchangeRatesForChainId = {\n ...this.state.contractExchangeRatesByChainId,\n [chainId]: {\n ...existingContractExchangeRatesForChainId,\n [nativeCurrency]: {\n ...existingContractExchangeRatesForChainId[nativeCurrency],\n ...newContractExchangeRates,\n },\n },\n };\n\n this.update({\n contractExchangeRates: updatedContractExchangeRates,\n contractExchangeRatesByChainId: updatedContractExchangeRatesForChainId,\n });\n updateSucceeded();\n } catch (error: unknown) {\n updateFailed(error);\n throw error;\n } finally {\n delete this.#inProcessExchangeRateUpdates[updateKey];\n }\n }\n\n /**\n * Uses the token prices service to retrieve exchange rates for tokens in a\n * particular currency.\n *\n * If the price API does not support the given chain ID, returns an empty\n * object.\n *\n * If the price API does not support the given currency, retrieves exchange\n * rates in a known currency instead, then converts those rates using the\n * exchange rate between the known currency and desired currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * exchange rates.\n * @returns A map from token address to its exchange rate in the native\n * currency, or an empty map if no exchange rates can be obtained for the\n * chain ID.\n */\n async #fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n if (!this.#tokenPricesService.validateChainIdSupported(chainId)) {\n return tokenAddresses.reduce((obj, tokenAddress) => {\n return {\n ...obj,\n [tokenAddress]: undefined,\n };\n }, {});\n }\n\n if (this.#tokenPricesService.validateCurrencySupported(nativeCurrency)) {\n return await this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n }\n\n return await this.#fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenAddresses,\n nativeCurrency,\n });\n }\n\n /**\n * Updates token rates for the given networkClientId\n *\n * @param networkClientId - The network client ID used to get a ticker value.\n * @returns The controller state.\n */\n async _executePoll(networkClientId: NetworkClientId): Promise<void> {\n const networkClient = this.getNetworkClientById(networkClientId);\n await this.updateExchangeRatesByChainId({\n chainId: networkClient.configuration.chainId,\n nativeCurrency: networkClient.configuration.ticker,\n });\n }\n\n /**\n * Retrieves prices in the given currency for the given tokens on the given\n * chain. Ensures that token addresses are checksum addresses.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const tokenPricesByTokenAddress = await reduceInBatchesSerially<\n Hex,\n Awaited<ReturnType<AbstractTokenPricesService['fetchTokenPrices']>>\n >({\n values: tokenAddresses,\n batchSize: TOKEN_PRICES_BATCH_SIZE,\n eachBatch: async (allTokenPricesByTokenAddress, batch) => {\n const tokenPricesByTokenAddressForBatch =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenAddresses: batch,\n chainId,\n currency: nativeCurrency,\n });\n\n return {\n ...allTokenPricesByTokenAddress,\n ...tokenPricesByTokenAddressForBatch,\n };\n },\n initialResult: {},\n });\n\n return Object.entries(tokenPricesByTokenAddress).reduce(\n (obj, [tokenAddress, tokenPrice]) => {\n return {\n ...obj,\n [tokenAddress]: tokenPrice?.value,\n };\n },\n {},\n );\n }\n\n /**\n * If the price API does not support a given native currency, then we need to\n * convert it to a fallback currency and feed that currency into the price\n * API, then convert the prices to our desired native currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenAddresses,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const [\n contractExchangeRates,\n fallbackCurrencyToNativeCurrencyConversionRate,\n ] = await Promise.all([\n this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId: this.config.chainId,\n nativeCurrency: FALL_BACK_VS_CURRENCY,\n }),\n getCurrencyConversionRate({\n from: FALL_BACK_VS_CURRENCY,\n to: nativeCurrency,\n }),\n ]);\n\n if (fallbackCurrencyToNativeCurrencyConversionRate === null) {\n return {};\n }\n\n return Object.entries(contractExchangeRates).reduce(\n (obj, [tokenAddress, tokenValue]) => {\n return {\n ...obj,\n [tokenAddress]: tokenValue\n ? tokenValue * fallbackCurrencyToNativeCurrencyConversionRate\n : undefined,\n };\n },\n {},\n );\n }\n}\n\n/**\n * A deferred Promise.\n *\n * A deferred Promise is one that can be resolved or rejected independently of\n * the Promise construction.\n */\ntype DeferredPromise = {\n /**\n * The Promise that has been deferred.\n */\n promise: Promise<void>;\n /**\n * A function that resolves the Promise.\n */\n resolve: () => void;\n /**\n * A function that rejects the Promise.\n */\n reject: (error: unknown) => void;\n};\n\n/**\n * Create a defered Promise.\n *\n * TODO: Migrate this to utils\n *\n * @param args - The arguments.\n * @param args.suppressUnhandledRejection - This option adds an empty error handler\n * to the Promise to suppress the UnhandledPromiseRejection error. This can be\n * useful if the deferred Promise is sometimes intentionally not used.\n * @returns A deferred Promise.\n */\nfunction createDeferredPromise({\n suppressUnhandledRejection = false,\n}: {\n suppressUnhandledRejection: boolean;\n}): DeferredPromise {\n let resolve: DeferredPromise['resolve'];\n let reject: DeferredPromise['reject'];\n const promise = new Promise<void>(\n (innerResolve: () => void, innerReject: () => void) => {\n resolve = innerResolve;\n reject = innerReject;\n },\n );\n\n if (suppressUnhandledRejection) {\n promise.catch((_error) => {\n // This handler is used to suppress the UnhandledPromiseRejection error\n });\n }\n\n // @ts-expect-error We know that these are assigned, but TypeScript doesn't\n return { promise, resolve, reject };\n}\n\nexport default TokenRatesController;\n"]}
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { Contract } from '@ethersproject/contracts';
3
+ import { Web3Provider } from '@ethersproject/providers';
3
4
  import type { AddApprovalRequest } from '@metamask/approval-controller';
4
5
  import type { BaseConfig, BaseState, RestrictedControllerMessenger } from '@metamask/base-controller';
5
6
  import { BaseControllerV1 } from '@metamask/base-controller';
@@ -7,7 +8,6 @@ import type { NetworkClientId, NetworkController, NetworkState } from '@metamask
7
8
  import type { PreferencesState } from '@metamask/preferences-controller';
8
9
  import type { Hex } from '@metamask/utils';
9
10
  import { EventEmitter } from 'events';
10
- import type { AssetsContractController } from './AssetsContractController';
11
11
  import type { TokenListState } from './TokenListController';
12
12
  import type { Token } from './TokenRatesController';
13
13
  /**
@@ -81,6 +81,7 @@ declare type AllowedActions = AddApprovalRequest;
81
81
  * The messenger of the {@link TokensController}.
82
82
  */
83
83
  export declare type TokensControllerMessenger = RestrictedControllerMessenger<typeof controllerName, AllowedActions, never, AllowedActions['type'], never>;
84
+ export declare const getDefaultTokensState: () => TokensState;
84
85
  /**
85
86
  * Controller that stores assets and exposes convenience methods
86
87
  */
@@ -103,7 +104,6 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
103
104
  * Name of this controller used during composition
104
105
  */
105
106
  name: string;
106
- private readonly getERC20TokenName;
107
107
  private readonly getNetworkClientById;
108
108
  /**
109
109
  * Creates a TokensController instance.
@@ -113,18 +113,16 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
113
113
  * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.
114
114
  * @param options.onNetworkDidChange - Allows subscribing to network controller networkDidChange events.
115
115
  * @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.
116
- * @param options.getERC20TokenName - Gets the ERC-20 token name.
117
116
  * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.
118
117
  * @param options.config - Initial options used to configure this controller.
119
118
  * @param options.state - Initial state to set on this controller.
120
119
  * @param options.messenger - The controller messenger.
121
120
  */
122
- constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkDidChange, onTokenListStateChange, getERC20TokenName, getNetworkClientById, config, state, messenger, }: {
121
+ constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkDidChange, onTokenListStateChange, getNetworkClientById, config, state, messenger, }: {
123
122
  chainId: Hex;
124
123
  onPreferencesStateChange: (listener: (preferencesState: PreferencesState) => void) => void;
125
124
  onNetworkDidChange: (listener: (networkState: NetworkState) => void) => void;
126
125
  onTokenListStateChange: (listener: (tokenListState: TokenListState) => void) => void;
127
- getERC20TokenName: AssetsContractController['getERC20TokenName'];
128
126
  getNetworkClientById: NetworkController['getNetworkClientById'];
129
127
  config?: Partial<TokensConfig>;
130
128
  state?: Partial<TokensState>;
@@ -201,6 +199,7 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
201
199
  * interface.
202
200
  */
203
201
  _detectIsERC721(tokenAddress: string, networkClientId?: NetworkClientId): Promise<any>;
202
+ _getProvider(networkClientId?: NetworkClientId): Web3Provider;
204
203
  _createEthersContract(tokenAddress: string, abi: string, networkClientId?: NetworkClientId): Contract;
205
204
  _generateRandomId(): string;
206
205
  /**
@@ -212,7 +211,7 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
212
211
  * @param options.type - The asset type.
213
212
  * @param options.interactingAddress - The address of the account that is requesting to watch the asset.
214
213
  * @param options.networkClientId - Network Client ID.
215
- * @returns Object containing a Promise resolving to the suggestedAsset address if accepted.
214
+ * @returns A promise that resolves if the asset was watched successfully, and rejects otherwise.
216
215
  */
217
216
  watchAsset({ asset, type, interactingAddress, networkClientId, }: {
218
217
  asset: Token;
@@ -1 +1 @@
1
- {"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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"}