@metamask-previews/assets-controllers 39.0.0-preview-c77aebdb → 39.0.0-preview-5c534570

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 (48) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/AccountTrackerController.d.cts +4 -4
  3. package/dist/AccountTrackerController.d.mts +4 -4
  4. package/dist/CurrencyRateController.cjs +3 -4
  5. package/dist/CurrencyRateController.cjs.map +1 -1
  6. package/dist/CurrencyRateController.d.cts +8 -8
  7. package/dist/CurrencyRateController.d.cts.map +1 -1
  8. package/dist/CurrencyRateController.d.mts +8 -8
  9. package/dist/CurrencyRateController.d.mts.map +1 -1
  10. package/dist/CurrencyRateController.mjs +3 -4
  11. package/dist/CurrencyRateController.mjs.map +1 -1
  12. package/dist/TokenBalancesController.cjs +36 -87
  13. package/dist/TokenBalancesController.cjs.map +1 -1
  14. package/dist/TokenBalancesController.d.cts +36 -34
  15. package/dist/TokenBalancesController.d.cts.map +1 -1
  16. package/dist/TokenBalancesController.d.mts +36 -34
  17. package/dist/TokenBalancesController.d.mts.map +1 -1
  18. package/dist/TokenBalancesController.mjs +37 -88
  19. package/dist/TokenBalancesController.mjs.map +1 -1
  20. package/dist/TokenDetectionController.d.cts +4 -4
  21. package/dist/TokenDetectionController.d.mts +4 -4
  22. package/dist/TokenListController.d.cts +4 -4
  23. package/dist/TokenListController.d.mts +4 -4
  24. package/dist/TokenRatesController.cjs +4 -4
  25. package/dist/TokenRatesController.cjs.map +1 -1
  26. package/dist/TokenRatesController.d.cts +4 -4
  27. package/dist/TokenRatesController.d.cts.map +1 -1
  28. package/dist/TokenRatesController.d.mts +4 -4
  29. package/dist/TokenRatesController.d.mts.map +1 -1
  30. package/dist/TokenRatesController.mjs +4 -4
  31. package/dist/TokenRatesController.mjs.map +1 -1
  32. package/dist/assetsUtil.cjs +2 -2
  33. package/dist/assetsUtil.cjs.map +1 -1
  34. package/dist/assetsUtil.d.cts +3 -3
  35. package/dist/assetsUtil.d.cts.map +1 -1
  36. package/dist/assetsUtil.d.mts +3 -3
  37. package/dist/assetsUtil.d.mts.map +1 -1
  38. package/dist/assetsUtil.mjs +2 -2
  39. package/dist/assetsUtil.mjs.map +1 -1
  40. package/dist/multicall.cjs +350 -0
  41. package/dist/multicall.cjs.map +1 -0
  42. package/dist/multicall.d.cts +26 -0
  43. package/dist/multicall.d.cts.map +1 -0
  44. package/dist/multicall.d.mts +26 -0
  45. package/dist/multicall.d.mts.map +1 -0
  46. package/dist/multicall.mjs +346 -0
  47. package/dist/multicall.mjs.map +1 -0
  48. package/package.json +7 -6
package/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Changed
11
+
12
+ - **BREAKING:** Bump `@metamask/network-controller` peer dependency from `^21.0.0` to `^22.0.0` ([#4841](https://github.com/MetaMask/core/pull/4841))
13
+
10
14
  ## [39.0.0]
11
15
 
12
16
  ### Changed
@@ -62,14 +62,14 @@ type AccountTrackerPollingInput = {
62
62
  networkClientId: NetworkClientId;
63
63
  };
64
64
  declare const AccountTrackerController_base: (abstract new (...args: any[]) => {
65
- readonly "__#786026@#intervalIds": Record<string, NodeJS.Timeout>;
66
- "__#786026@#intervalLength": number | undefined;
65
+ readonly "__#787826@#intervalIds": Record<string, NodeJS.Timeout>;
66
+ "__#787826@#intervalLength": number | undefined;
67
67
  setIntervalLength(intervalLength: number): void;
68
68
  getIntervalLength(): number | undefined;
69
69
  _startPolling(input: AccountTrackerPollingInput): void;
70
70
  _stopPollingByPollingTokenSetId(key: string): void;
71
- readonly "__#786018@#pollingTokenSets": Map<string, Set<string>>;
72
- "__#786018@#callbacks": Map<string, Set<(input: AccountTrackerPollingInput) => void>>;
71
+ readonly "__#787818@#pollingTokenSets": Map<string, Set<string>>;
72
+ "__#787818@#callbacks": Map<string, Set<(input: AccountTrackerPollingInput) => void>>;
73
73
  _executePoll(input: AccountTrackerPollingInput): Promise<void>;
74
74
  /**
75
75
  * The action that can be performed to get the state of the {@link AccountTrackerController}.
@@ -62,14 +62,14 @@ type AccountTrackerPollingInput = {
62
62
  networkClientId: NetworkClientId;
63
63
  };
64
64
  declare const AccountTrackerController_base: (abstract new (...args: any[]) => {
65
- readonly "__#786026@#intervalIds": Record<string, NodeJS.Timeout>;
66
- "__#786026@#intervalLength": number | undefined;
65
+ readonly "__#787826@#intervalIds": Record<string, NodeJS.Timeout>;
66
+ "__#787826@#intervalLength": number | undefined;
67
67
  setIntervalLength(intervalLength: number): void;
68
68
  getIntervalLength(): number | undefined;
69
69
  _startPolling(input: AccountTrackerPollingInput): void;
70
70
  _stopPollingByPollingTokenSetId(key: string): void;
71
- readonly "__#786018@#pollingTokenSets": Map<string, Set<string>>;
72
- "__#786018@#callbacks": Map<string, Set<(input: AccountTrackerPollingInput) => void>>;
71
+ readonly "__#787818@#pollingTokenSets": Map<string, Set<string>>;
72
+ "__#787818@#callbacks": Map<string, Set<(input: AccountTrackerPollingInput) => void>>;
73
73
  _executePoll(input: AccountTrackerPollingInput): Promise<void>;
74
74
  /**
75
75
  * The action that can be performed to get the state of the {@link AccountTrackerController}.
@@ -144,11 +144,10 @@ class CurrencyRateController extends (0, polling_controller_1.StaticIntervalPoll
144
144
  * Updates exchange rate for the current currency.
145
145
  *
146
146
  * @param input - The input for the poll.
147
- * @param input.networkClientId - The network client ID used to get a ticker value.
147
+ * @param input.nativeCurrency - The native currency symbol to poll prices for.
148
148
  */
149
- async _executePoll({ networkClientId, }) {
150
- const networkClient = this.messagingSystem.call('NetworkController:getNetworkClientById', networkClientId);
151
- await this.updateExchangeRate(networkClient.configuration.ticker);
149
+ async _executePoll({ nativeCurrency, }) {
150
+ await this.updateExchangeRate(nativeCurrency);
152
151
  }
153
152
  }
154
153
  exports.CurrencyRateController = CurrencyRateController;
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.cjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { Mutex } from 'async-mutex';\n\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare-service';\n\n/**\n * @type CurrencyRateState\n * @property currencyRates - Object keyed by native currency\n * @property currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions = NetworkControllerGetNetworkClientByIdAction;\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents,\n AllowedActions['type'],\n never\n>;\n\nconst metadata = {\n currentCurrency: { persist: true, anonymous: true },\n currencyRates: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n networkClientId: NetworkClientId;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly fetchExchangeRate;\n\n private readonly 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.setIntervalLength(interval);\n this.fetchExchangeRate = fetchExchangeRate;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n nativeCurrencies.forEach(this.updateExchangeRate.bind(this));\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pair.\n *\n * @param nativeCurrency - The ticker symbol for the chain.\n */\n async updateExchangeRate(nativeCurrency: string): Promise<void> {\n const releaseLock = await this.mutex.acquire();\n const { currentCurrency, currencyRates } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n\n // For preloaded testnets (Goerli, Sepolia) 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 let shouldUpdateState = true;\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 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 // Don't update state on transient / unexpected errors\n shouldUpdateState = false;\n throw error;\n }\n } finally {\n try {\n if (shouldUpdateState) {\n this.update(() => {\n return {\n currencyRates: {\n ...currencyRates,\n [nativeCurrency]: {\n conversionDate,\n conversionRate,\n usdConversionRate,\n },\n },\n currentCurrency,\n };\n });\n }\n } finally {\n releaseLock();\n }\n }\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.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.networkClientId - The network client ID used to get a ticker value.\n */\n async _executePoll({\n networkClientId,\n }: CurrencyRatePollingInput): Promise<void> {\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n await this.updateExchangeRate(networkClient.configuration.ticker);\n }\n}\n\nexport default CurrencyRateController;\n"]}
1
+ {"version":3,"file":"CurrencyRateController.cjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { NetworkControllerGetNetworkClientByIdAction } from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { Mutex } from 'async-mutex';\n\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare-service';\n\n/**\n * @type CurrencyRateState\n * @property currencyRates - Object keyed by native currency\n * @property currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions = NetworkControllerGetNetworkClientByIdAction;\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents,\n AllowedActions['type'],\n never\n>;\n\nconst metadata = {\n currentCurrency: { persist: true, anonymous: true },\n currencyRates: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrency: string;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly fetchExchangeRate;\n\n private readonly 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.setIntervalLength(interval);\n this.fetchExchangeRate = fetchExchangeRate;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n nativeCurrencies.forEach(this.updateExchangeRate.bind(this));\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pair.\n *\n * @param nativeCurrency - The ticker symbol for the chain.\n */\n async updateExchangeRate(nativeCurrency: string): Promise<void> {\n const releaseLock = await this.mutex.acquire();\n const { currentCurrency, currencyRates } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n\n // For preloaded testnets (Goerli, Sepolia) 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 let shouldUpdateState = true;\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 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 // Don't update state on transient / unexpected errors\n shouldUpdateState = false;\n throw error;\n }\n } finally {\n try {\n if (shouldUpdateState) {\n this.update(() => {\n return {\n currencyRates: {\n ...currencyRates,\n [nativeCurrency]: {\n conversionDate,\n conversionRate,\n usdConversionRate,\n },\n },\n currentCurrency,\n };\n });\n }\n } finally {\n releaseLock();\n }\n }\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.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrency - The native currency symbol to poll prices for.\n */\n async _executePoll({\n nativeCurrency,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrency);\n }\n}\n\nexport default CurrencyRateController;\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { RestrictedControllerMessenger, ControllerGetStateAction, ControllerStateChangeEvent } from "@metamask/base-controller";
2
- import type { NetworkClientId, NetworkControllerGetNetworkClientByIdAction } from "@metamask/network-controller";
2
+ import type { NetworkControllerGetNetworkClientByIdAction } from "@metamask/network-controller";
3
3
  import { fetchExchangeRate as defaultFetchExchangeRate } from "./crypto-compare-service/index.cjs";
4
4
  /**
5
5
  * @type CurrencyRateState
@@ -26,17 +26,17 @@ type AllowedActions = NetworkControllerGetNetworkClientByIdAction;
26
26
  type CurrencyRateMessenger = RestrictedControllerMessenger<typeof name, CurrencyRateControllerActions | AllowedActions, CurrencyRateControllerEvents, AllowedActions['type'], never>;
27
27
  /** The input to start polling for the {@link CurrencyRateController} */
28
28
  type CurrencyRatePollingInput = {
29
- networkClientId: NetworkClientId;
29
+ nativeCurrency: string;
30
30
  };
31
31
  declare const CurrencyRateController_base: (abstract new (...args: any[]) => {
32
- readonly "__#786026@#intervalIds": Record<string, NodeJS.Timeout>;
33
- "__#786026@#intervalLength": number | undefined;
32
+ readonly "__#787826@#intervalIds": Record<string, NodeJS.Timeout>;
33
+ "__#787826@#intervalLength": number | undefined;
34
34
  setIntervalLength(intervalLength: number): void;
35
35
  getIntervalLength(): number | undefined;
36
36
  _startPolling(input: CurrencyRatePollingInput): void;
37
37
  _stopPollingByPollingTokenSetId(key: string): void;
38
- readonly "__#786018@#pollingTokenSets": Map<string, Set<string>>;
39
- "__#786018@#callbacks": Map<string, Set<(input: CurrencyRatePollingInput) => void>>;
38
+ readonly "__#787818@#pollingTokenSets": Map<string, Set<string>>;
39
+ "__#787818@#callbacks": Map<string, Set<(input: CurrencyRatePollingInput) => void>>;
40
40
  _executePoll(input: CurrencyRatePollingInput): Promise<void>;
41
41
  startPolling(input: CurrencyRatePollingInput): string;
42
42
  stopAllPolling(): void;
@@ -90,9 +90,9 @@ export declare class CurrencyRateController extends CurrencyRateController_base<
90
90
  * Updates exchange rate for the current currency.
91
91
  *
92
92
  * @param input - The input for the poll.
93
- * @param input.networkClientId - The network client ID used to get a ticker value.
93
+ * @param input.nativeCurrency - The native currency symbol to poll prices for.
94
94
  */
95
- _executePoll({ networkClientId, }: CurrencyRatePollingInput): Promise<void>;
95
+ _executePoll({ nativeCurrency, }: CurrencyRatePollingInput): Promise<void>;
96
96
  }
97
97
  export default CurrencyRateController;
98
98
  //# sourceMappingURL=CurrencyRateController.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.d.cts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AAKnC,OAAO,KAAK,EACV,eAAe,EACf,2CAA2C,EAC5C,qCAAqC;AAItC,OAAO,EAAE,iBAAiB,IAAI,wBAAwB,EAAE,2CAAiC;AAEzF;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE,KAAK,qBAAqB,GAAG,6BAA6B,CACxD,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,EAC5B,cAAc,CAAC,MAAM,CAAC,EACtB,KAAK,CACN,CAAC;AAkBF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC;;;;;;;;;OASG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,SAAS,EACT,KAAK,EACL,iBAA4C,GAC7C,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,iBAAiB,CAAC,EAAE,OAAO,wBAAwB,CAAC;KACrD;IAYD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAkBhD;;;;OAIG;IACG,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqE/D;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,eAAe,GAChB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAO5C;AAED,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"CurrencyRateController.d.cts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,2CAA2C,EAAE,qCAAqC;AAIhG,OAAO,EAAE,iBAAiB,IAAI,wBAAwB,EAAE,2CAAiC;AAEzF;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE,KAAK,qBAAqB,GAAG,6BAA6B,CACxD,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,EAC5B,cAAc,CAAC,MAAM,CAAC,EACtB,KAAK,CACN,CAAC;AAkBF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC;;;;;;;;;OASG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,SAAS,EACT,KAAK,EACL,iBAA4C,GAC7C,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,iBAAiB,CAAC,EAAE,OAAO,wBAAwB,CAAC;KACrD;IAYD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAkBhD;;;;OAIG;IACG,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqE/D;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,cAAc,GACf,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { RestrictedControllerMessenger, ControllerGetStateAction, ControllerStateChangeEvent } from "@metamask/base-controller";
2
- import type { NetworkClientId, NetworkControllerGetNetworkClientByIdAction } from "@metamask/network-controller";
2
+ import type { NetworkControllerGetNetworkClientByIdAction } from "@metamask/network-controller";
3
3
  import { fetchExchangeRate as defaultFetchExchangeRate } from "./crypto-compare-service/index.mjs";
4
4
  /**
5
5
  * @type CurrencyRateState
@@ -26,17 +26,17 @@ type AllowedActions = NetworkControllerGetNetworkClientByIdAction;
26
26
  type CurrencyRateMessenger = RestrictedControllerMessenger<typeof name, CurrencyRateControllerActions | AllowedActions, CurrencyRateControllerEvents, AllowedActions['type'], never>;
27
27
  /** The input to start polling for the {@link CurrencyRateController} */
28
28
  type CurrencyRatePollingInput = {
29
- networkClientId: NetworkClientId;
29
+ nativeCurrency: string;
30
30
  };
31
31
  declare const CurrencyRateController_base: (abstract new (...args: any[]) => {
32
- readonly "__#786026@#intervalIds": Record<string, NodeJS.Timeout>;
33
- "__#786026@#intervalLength": number | undefined;
32
+ readonly "__#787826@#intervalIds": Record<string, NodeJS.Timeout>;
33
+ "__#787826@#intervalLength": number | undefined;
34
34
  setIntervalLength(intervalLength: number): void;
35
35
  getIntervalLength(): number | undefined;
36
36
  _startPolling(input: CurrencyRatePollingInput): void;
37
37
  _stopPollingByPollingTokenSetId(key: string): void;
38
- readonly "__#786018@#pollingTokenSets": Map<string, Set<string>>;
39
- "__#786018@#callbacks": Map<string, Set<(input: CurrencyRatePollingInput) => void>>;
38
+ readonly "__#787818@#pollingTokenSets": Map<string, Set<string>>;
39
+ "__#787818@#callbacks": Map<string, Set<(input: CurrencyRatePollingInput) => void>>;
40
40
  _executePoll(input: CurrencyRatePollingInput): Promise<void>;
41
41
  startPolling(input: CurrencyRatePollingInput): string;
42
42
  stopAllPolling(): void;
@@ -90,9 +90,9 @@ export declare class CurrencyRateController extends CurrencyRateController_base<
90
90
  * Updates exchange rate for the current currency.
91
91
  *
92
92
  * @param input - The input for the poll.
93
- * @param input.networkClientId - The network client ID used to get a ticker value.
93
+ * @param input.nativeCurrency - The native currency symbol to poll prices for.
94
94
  */
95
- _executePoll({ networkClientId, }: CurrencyRatePollingInput): Promise<void>;
95
+ _executePoll({ nativeCurrency, }: CurrencyRatePollingInput): Promise<void>;
96
96
  }
97
97
  export default CurrencyRateController;
98
98
  //# sourceMappingURL=CurrencyRateController.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.d.mts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AAKnC,OAAO,KAAK,EACV,eAAe,EACf,2CAA2C,EAC5C,qCAAqC;AAItC,OAAO,EAAE,iBAAiB,IAAI,wBAAwB,EAAE,2CAAiC;AAEzF;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE,KAAK,qBAAqB,GAAG,6BAA6B,CACxD,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,EAC5B,cAAc,CAAC,MAAM,CAAC,EACtB,KAAK,CACN,CAAC;AAkBF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC;;;;;;;;;OASG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,SAAS,EACT,KAAK,EACL,iBAA4C,GAC7C,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,iBAAiB,CAAC,EAAE,OAAO,wBAAwB,CAAC;KACrD;IAYD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAkBhD;;;;OAIG;IACG,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqE/D;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,eAAe,GAChB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAO5C;AAED,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"CurrencyRateController.d.mts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,2CAA2C,EAAE,qCAAqC;AAIhG,OAAO,EAAE,iBAAiB,IAAI,wBAAwB,EAAE,2CAAiC;AAEzF;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE,KAAK,qBAAqB,GAAG,6BAA6B,CACxD,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,EAC5B,cAAc,CAAC,MAAM,CAAC,EACtB,KAAK,CACN,CAAC;AAkBF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC;;;;;;;;;OASG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,SAAS,EACT,KAAK,EACL,iBAA4C,GAC7C,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,iBAAiB,CAAC,EAAE,OAAO,wBAAwB,CAAC;KACrD;IAYD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAkBhD;;;;OAIG;IACG,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqE/D;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,cAAc,GACf,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
@@ -141,11 +141,10 @@ export class CurrencyRateController extends StaticIntervalPollingController() {
141
141
  * Updates exchange rate for the current currency.
142
142
  *
143
143
  * @param input - The input for the poll.
144
- * @param input.networkClientId - The network client ID used to get a ticker value.
144
+ * @param input.nativeCurrency - The native currency symbol to poll prices for.
145
145
  */
146
- async _executePoll({ networkClientId, }) {
147
- const networkClient = this.messagingSystem.call('NetworkController:getNetworkClientById', networkClientId);
148
- await this.updateExchangeRate(networkClient.configuration.ticker);
146
+ async _executePoll({ nativeCurrency, }) {
147
+ await this.updateExchangeRate(nativeCurrency);
149
148
  }
150
149
  }
151
150
  export default CurrencyRateController;
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.mjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { Mutex } from 'async-mutex';\n\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare-service';\n\n/**\n * @type CurrencyRateState\n * @property currencyRates - Object keyed by native currency\n * @property currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions = NetworkControllerGetNetworkClientByIdAction;\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents,\n AllowedActions['type'],\n never\n>;\n\nconst metadata = {\n currentCurrency: { persist: true, anonymous: true },\n currencyRates: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n networkClientId: NetworkClientId;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly fetchExchangeRate;\n\n private readonly 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.setIntervalLength(interval);\n this.fetchExchangeRate = fetchExchangeRate;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n nativeCurrencies.forEach(this.updateExchangeRate.bind(this));\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pair.\n *\n * @param nativeCurrency - The ticker symbol for the chain.\n */\n async updateExchangeRate(nativeCurrency: string): Promise<void> {\n const releaseLock = await this.mutex.acquire();\n const { currentCurrency, currencyRates } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n\n // For preloaded testnets (Goerli, Sepolia) 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 let shouldUpdateState = true;\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 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 // Don't update state on transient / unexpected errors\n shouldUpdateState = false;\n throw error;\n }\n } finally {\n try {\n if (shouldUpdateState) {\n this.update(() => {\n return {\n currencyRates: {\n ...currencyRates,\n [nativeCurrency]: {\n conversionDate,\n conversionRate,\n usdConversionRate,\n },\n },\n currentCurrency,\n };\n });\n }\n } finally {\n releaseLock();\n }\n }\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.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.networkClientId - The network client ID used to get a ticker value.\n */\n async _executePoll({\n networkClientId,\n }: CurrencyRatePollingInput): Promise<void> {\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n await this.updateExchangeRate(networkClient.configuration.ticker);\n }\n}\n\nexport default CurrencyRateController;\n"]}
1
+ {"version":3,"file":"CurrencyRateController.mjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { NetworkControllerGetNetworkClientByIdAction } from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { Mutex } from 'async-mutex';\n\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare-service';\n\n/**\n * @type CurrencyRateState\n * @property currencyRates - Object keyed by native currency\n * @property currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions = NetworkControllerGetNetworkClientByIdAction;\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents,\n AllowedActions['type'],\n never\n>;\n\nconst metadata = {\n currentCurrency: { persist: true, anonymous: true },\n currencyRates: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrency: string;\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly fetchExchangeRate;\n\n private readonly 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.setIntervalLength(interval);\n this.fetchExchangeRate = fetchExchangeRate;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n nativeCurrencies.forEach(this.updateExchangeRate.bind(this));\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pair.\n *\n * @param nativeCurrency - The ticker symbol for the chain.\n */\n async updateExchangeRate(nativeCurrency: string): Promise<void> {\n const releaseLock = await this.mutex.acquire();\n const { currentCurrency, currencyRates } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n\n // For preloaded testnets (Goerli, Sepolia) 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 let shouldUpdateState = true;\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 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 // Don't update state on transient / unexpected errors\n shouldUpdateState = false;\n throw error;\n }\n } finally {\n try {\n if (shouldUpdateState) {\n this.update(() => {\n return {\n currencyRates: {\n ...currencyRates,\n [nativeCurrency]: {\n conversionDate,\n conversionRate,\n usdConversionRate,\n },\n },\n currentCurrency,\n };\n });\n }\n } finally {\n releaseLock();\n }\n }\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.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrency - The native currency symbol to poll prices for.\n */\n async _executePoll({\n nativeCurrency,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrency);\n }\n}\n\nexport default CurrencyRateController;\n"]}
@@ -1,24 +1,16 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- 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");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _TokenBalancesController_handle, _TokenBalancesController_interval, _TokenBalancesController_tokens, _TokenBalancesController_disabled;
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
3
  exports.TokenBalancesController = exports.getDefaultTokenBalancesState = void 0;
16
- const base_controller_1 = require("@metamask/base-controller");
4
+ const contracts_1 = require("@ethersproject/contracts");
5
+ const providers_1 = require("@ethersproject/providers");
17
6
  const controller_utils_1 = require("@metamask/controller-utils");
7
+ const metamask_eth_abis_1 = require("@metamask/metamask-eth-abis");
8
+ const polling_controller_1 = require("@metamask/polling-controller");
9
+ const multicall_1 = require("./multicall.cjs");
18
10
  const DEFAULT_INTERVAL = 180000;
19
11
  const controllerName = 'TokenBalancesController';
20
12
  const metadata = {
21
- contractBalances: { persist: true, anonymous: false },
13
+ tokenBalances: { persist: true, anonymous: false },
22
14
  };
23
15
  /**
24
16
  * Get the default TokenBalancesController state.
@@ -27,7 +19,7 @@ const metadata = {
27
19
  */
28
20
  function getDefaultTokenBalancesState() {
29
21
  return {
30
- contractBalances: {},
22
+ tokenBalances: {},
31
23
  };
32
24
  }
33
25
  exports.getDefaultTokenBalancesState = getDefaultTokenBalancesState;
@@ -35,18 +27,16 @@ exports.getDefaultTokenBalancesState = getDefaultTokenBalancesState;
35
27
  * Controller that passively polls on a set interval token balances
36
28
  * for tokens stored in the TokensController
37
29
  */
38
- class TokenBalancesController extends base_controller_1.BaseController {
30
+ class TokenBalancesController extends (0, polling_controller_1.StaticIntervalPollingController)() {
39
31
  /**
40
32
  * Construct a Token Balances Controller.
41
33
  *
42
34
  * @param options - The controller options.
43
35
  * @param options.interval - Polling interval used to fetch new token balances.
44
- * @param options.tokens - List of tokens to track balances for.
45
- * @param options.disabled - If set to true, all tracked tokens contract balances updates are blocked.
46
36
  * @param options.state - Initial state to set on this controller.
47
37
  * @param options.messenger - The controller restricted messenger.
48
38
  */
49
- constructor({ interval = DEFAULT_INTERVAL, tokens = [], disabled = false, messenger, state = {}, }) {
39
+ constructor({ interval = DEFAULT_INTERVAL, messenger, state = {}, }) {
50
40
  super({
51
41
  name: controllerName,
52
42
  metadata,
@@ -56,81 +46,40 @@ class TokenBalancesController extends base_controller_1.BaseController {
56
46
  ...state,
57
47
  },
58
48
  });
59
- _TokenBalancesController_handle.set(this, void 0);
60
- _TokenBalancesController_interval.set(this, void 0);
61
- _TokenBalancesController_tokens.set(this, void 0);
62
- _TokenBalancesController_disabled.set(this, void 0);
63
- __classPrivateFieldSet(this, _TokenBalancesController_disabled, disabled, "f");
64
- __classPrivateFieldSet(this, _TokenBalancesController_interval, interval, "f");
65
- __classPrivateFieldSet(this, _TokenBalancesController_tokens, tokens, "f");
66
- this.messagingSystem.subscribe('TokensController:stateChange', ({ tokens: newTokens, detectedTokens }) => {
67
- __classPrivateFieldSet(this, _TokenBalancesController_tokens, [...newTokens, ...detectedTokens], "f");
68
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
69
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
70
- this.updateBalances();
71
- });
72
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
73
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
74
- this.poll();
75
- }
76
- /**
77
- * Allows controller to update tracked tokens contract balances.
78
- */
79
- enable() {
80
- __classPrivateFieldSet(this, _TokenBalancesController_disabled, false, "f");
81
- }
82
- /**
83
- * Blocks controller from updating tracked tokens contract balances.
84
- */
85
- disable() {
86
- __classPrivateFieldSet(this, _TokenBalancesController_disabled, true, "f");
87
- }
88
- /**
89
- * Starts a new polling interval.
90
- *
91
- * @param interval - Polling interval used to fetch new token balances.
92
- */
93
- async poll(interval) {
94
- if (interval) {
95
- __classPrivateFieldSet(this, _TokenBalancesController_interval, interval, "f");
96
- }
97
- if (__classPrivateFieldGet(this, _TokenBalancesController_handle, "f")) {
98
- clearTimeout(__classPrivateFieldGet(this, _TokenBalancesController_handle, "f"));
99
- }
100
- await (0, controller_utils_1.safelyExecute)(() => this.updateBalances());
101
- __classPrivateFieldSet(this, _TokenBalancesController_handle, setTimeout(() => {
102
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
103
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
104
- this.poll(__classPrivateFieldGet(this, _TokenBalancesController_interval, "f"));
105
- }, __classPrivateFieldGet(this, _TokenBalancesController_interval, "f")), "f");
49
+ this.setIntervalLength(interval);
106
50
  }
107
51
  /**
108
- * Updates balances for all tokens.
52
+ * Polls for erc20 token balances.
53
+ * @param input - The input for the poll.
54
+ * @param input.networkClientId - The network client id to poll with.
55
+ * @param input.tokensPerAccount - A mapping from account addresses to token addresses to poll.
109
56
  */
110
- async updateBalances() {
111
- if (__classPrivateFieldGet(this, _TokenBalancesController_disabled, "f")) {
112
- return;
113
- }
114
- const selectedInternalAccount = this.messagingSystem.call('AccountsController:getSelectedAccount');
115
- const newContractBalances = {};
116
- for (const token of __classPrivateFieldGet(this, _TokenBalancesController_tokens, "f")) {
117
- const { address } = token;
118
- try {
119
- const balance = await this.messagingSystem.call('AssetsContractController:getERC20BalanceOf', address, selectedInternalAccount.address);
120
- newContractBalances[address] = (0, controller_utils_1.toHex)(balance);
121
- token.hasBalanceError = false;
122
- }
123
- catch (error) {
124
- newContractBalances[address] = (0, controller_utils_1.toHex)(0);
125
- token.hasBalanceError = true;
126
- }
127
- }
57
+ async _executePoll({ networkClientId, tokensPerAccount, }) {
58
+ const networkClient = this.messagingSystem.call(`NetworkController:getNetworkClientById`, networkClientId);
59
+ const { chainId } = networkClient.configuration;
60
+ const provider = new providers_1.Web3Provider(networkClient.provider);
61
+ const accountTokenPairs = Object.entries(tokensPerAccount).flatMap(([accountAddress, tokenAddresses]) => tokenAddresses.map((tokenAddress) => ({
62
+ accountAddress: accountAddress,
63
+ tokenAddress,
64
+ })));
65
+ const calls = accountTokenPairs.map(({ accountAddress, tokenAddress }) => ({
66
+ contract: new contracts_1.Contract(tokenAddress, metamask_eth_abis_1.abiERC20, provider),
67
+ functionSignature: 'balanceOf(address)',
68
+ arguments: [accountAddress],
69
+ }));
70
+ const results = await (0, multicall_1.multicallOrFallback)(calls, chainId, provider);
128
71
  this.update((state) => {
129
- state.contractBalances = newContractBalances;
72
+ var _a, _b;
73
+ for (let i = 0; i < results.length; i++) {
74
+ const { success, value } = results[i];
75
+ if (success) {
76
+ const { accountAddress, tokenAddress } = accountTokenPairs[i];
77
+ ((_b = ((_a = state.tokenBalances)[accountAddress] ?? (_a[accountAddress] = {})))[chainId] ?? (_b[chainId] = {}))[tokenAddress] = (0, controller_utils_1.toHex)(value);
78
+ }
79
+ }
130
80
  });
131
81
  }
132
82
  }
133
83
  exports.TokenBalancesController = TokenBalancesController;
134
- _TokenBalancesController_handle = new WeakMap(), _TokenBalancesController_interval = new WeakMap(), _TokenBalancesController_tokens = new WeakMap(), _TokenBalancesController_disabled = new WeakMap();
135
84
  exports.default = TokenBalancesController;
136
85
  //# sourceMappingURL=TokenBalancesController.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TokenBalancesController.cjs","sourceRoot":"","sources":["../src/TokenBalancesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountsControllerGetSelectedAccountAction } from '@metamask/accounts-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { safelyExecute, toHex } from '@metamask/controller-utils';\n\nimport type { AssetsContractControllerGetERC20BalanceOfAction } from './AssetsContractController';\nimport type { Token } from './TokenRatesController';\nimport type { TokensControllerStateChangeEvent } from './TokensController';\n\nconst DEFAULT_INTERVAL = 180000;\n\nconst controllerName = 'TokenBalancesController';\n\nconst metadata = {\n contractBalances: { persist: true, anonymous: false },\n};\n\n/**\n * Token balances controller options\n * @property interval - Polling interval used to fetch new token balances.\n * @property tokens - List of tokens to track balances for.\n * @property disabled - If set to true, all tracked tokens contract balances updates are blocked.\n */\ntype TokenBalancesControllerOptions = {\n interval?: number;\n tokens?: Token[];\n disabled?: boolean;\n messenger: TokenBalancesControllerMessenger;\n state?: Partial<TokenBalancesControllerState>;\n};\n\n/**\n * Represents a mapping of hash token contract addresses to their balances.\n */\ntype ContractBalances = Record<string, string>;\n\n/**\n * Token balances controller state\n * @property contractBalances - Hash of token contract addresses to balances\n */\nexport type TokenBalancesControllerState = {\n contractBalances: ContractBalances;\n};\n\nexport type TokenBalancesControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenBalancesControllerState\n>;\n\nexport type TokenBalancesControllerActions =\n TokenBalancesControllerGetStateAction;\n\nexport type AllowedActions =\n | AccountsControllerGetSelectedAccountAction\n | AssetsContractControllerGetERC20BalanceOfAction;\n\nexport type TokenBalancesControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n TokenBalancesControllerState\n >;\n\nexport type TokenBalancesControllerEvents =\n TokenBalancesControllerStateChangeEvent;\n\nexport type AllowedEvents = TokensControllerStateChangeEvent;\n\nexport type TokenBalancesControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenBalancesControllerActions | AllowedActions,\n TokenBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Get the default TokenBalancesController state.\n *\n * @returns The default TokenBalancesController state.\n */\nexport function getDefaultTokenBalancesState(): TokenBalancesControllerState {\n return {\n contractBalances: {},\n };\n}\n\n/**\n * Controller that passively polls on a set interval token balances\n * for tokens stored in the TokensController\n */\nexport class TokenBalancesController extends BaseController<\n typeof controllerName,\n TokenBalancesControllerState,\n TokenBalancesControllerMessenger\n> {\n #handle?: ReturnType<typeof setTimeout>;\n\n #interval: number;\n\n #tokens: Token[];\n\n #disabled: boolean;\n\n /**\n * Construct a Token Balances Controller.\n *\n * @param options - The controller options.\n * @param options.interval - Polling interval used to fetch new token balances.\n * @param options.tokens - List of tokens to track balances for.\n * @param options.disabled - If set to true, all tracked tokens contract balances updates are blocked.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller restricted messenger.\n */\n constructor({\n interval = DEFAULT_INTERVAL,\n tokens = [],\n disabled = false,\n messenger,\n state = {},\n }: TokenBalancesControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultTokenBalancesState(),\n ...state,\n },\n });\n\n this.#disabled = disabled;\n this.#interval = interval;\n this.#tokens = tokens;\n\n this.messagingSystem.subscribe(\n 'TokensController:stateChange',\n ({ tokens: newTokens, detectedTokens }) => {\n this.#tokens = [...newTokens, ...detectedTokens];\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.updateBalances();\n },\n );\n\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.poll();\n }\n\n /**\n * Allows controller to update tracked tokens contract balances.\n */\n enable() {\n this.#disabled = false;\n }\n\n /**\n * Blocks controller from updating tracked tokens contract balances.\n */\n disable() {\n this.#disabled = true;\n }\n\n /**\n * Starts a new polling interval.\n *\n * @param interval - Polling interval used to fetch new token balances.\n */\n async poll(interval?: number): Promise<void> {\n if (interval) {\n this.#interval = interval;\n }\n\n if (this.#handle) {\n clearTimeout(this.#handle);\n }\n\n await safelyExecute(() => this.updateBalances());\n\n this.#handle = setTimeout(() => {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.poll(this.#interval);\n }, this.#interval);\n }\n\n /**\n * Updates balances for all tokens.\n */\n async updateBalances() {\n if (this.#disabled) {\n return;\n }\n const selectedInternalAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedAccount',\n );\n\n const newContractBalances: ContractBalances = {};\n for (const token of this.#tokens) {\n const { address } = token;\n try {\n const balance = await this.messagingSystem.call(\n 'AssetsContractController:getERC20BalanceOf',\n address,\n selectedInternalAccount.address,\n );\n newContractBalances[address] = toHex(balance);\n token.hasBalanceError = false;\n } catch (error) {\n newContractBalances[address] = toHex(0);\n token.hasBalanceError = true;\n }\n }\n\n this.update((state) => {\n state.contractBalances = newContractBalances;\n });\n }\n}\n\nexport default TokenBalancesController;\n"]}
1
+ {"version":3,"file":"TokenBalancesController.cjs","sourceRoot":"","sources":["../src/TokenBalancesController.ts"],"names":[],"mappings":";;;AAAA,wDAAoD;AACpD,wDAAwD;AAMxD,iEAAmD;AACnD,mEAAuD;AAKvD,qEAA+E;AAI/E,+CAAkD;AAGlD,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEhC,MAAM,cAAc,GAAG,yBAAyB,CAAC;AAEjD,MAAM,QAAQ,GAAG;IACf,aAAa,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;CACnD,CAAC;AAwDF;;;;GAIG;AACH,SAAgB,4BAA4B;IAC1C,OAAO;QACL,aAAa,EAAE,EAAE;KAClB,CAAC;AACJ,CAAC;AAJD,oEAIC;AAQD;;;GAGG;AACH,MAAa,uBAAwB,SAAQ,IAAA,oDAA+B,GAI3E;IACC;;;;;;;OAOG;IACH,YAAY,EACV,QAAQ,GAAG,gBAAgB,EAC3B,SAAS,EACT,KAAK,GAAG,EAAE,GACqB;QAC/B,KAAK,CAAC;YACJ,IAAI,EAAE,cAAc;YACpB,QAAQ;YACR,SAAS;YACT,KAAK,EAAE;gBACL,GAAG,4BAA4B,EAAE;gBACjC,GAAG,KAAK;aACT;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,EACjB,eAAe,EACf,gBAAgB,GACU;QAC1B,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC7C,wCAAwC,EACxC,eAAe,CAChB,CAAC;QAEF,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,aAAa,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,wBAAY,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAE1D,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAChE,CAAC,CAAC,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,CACnC,cAAc,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YACpC,cAAc,EAAE,cAAqB;YACrC,YAAY;SACb,CAAC,CAAC,CACN,CAAC;QAEF,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;YACzE,QAAQ,EAAE,IAAI,oBAAQ,CAAC,YAAY,EAAE,4BAAQ,EAAE,QAAQ,CAAC;YACxD,iBAAiB,EAAE,oBAAoB;YACvC,SAAS,EAAE,CAAC,cAAc,CAAC;SAC5B,CAAC,CAAC,CAAC;QAEJ,MAAM,OAAO,GAAG,MAAM,IAAA,+BAAmB,EAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEpE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;;YACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACvC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBAEtC,IAAI,OAAO,EAAE;oBACX,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;oBAC9D,OAAC,OAAC,KAAK,CAAC,aAAa,EAAC,cAAc,SAAd,cAAc,IAAM,EAAE,EAAC,EAAC,OAAO,SAAP,OAAO,IAAM,EAAE,EAAC,CAC5D,YAAY,CACb,GAAG,IAAA,wBAAK,EAAC,KAAW,CAAC,CAAC;iBACxB;aACF;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA9ED,0DA8EC;AAED,kBAAe,uBAAuB,CAAC","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport type BN from 'bn.js';\n\nimport { multicallOrFallback } from './multicall';\nimport type { TokensControllerStateChangeEvent } from './TokensController';\n\nconst DEFAULT_INTERVAL = 180000;\n\nconst controllerName = 'TokenBalancesController';\n\nconst metadata = {\n tokenBalances: { persist: true, anonymous: false },\n};\n\n/**\n * Token balances controller options\n * @property interval - Polling interval used to fetch new token balances.\n * @property messenger - A controller messenger.\n * @property state - Initial state for the controller.\n */\ntype TokenBalancesControllerOptions = {\n interval?: number;\n messenger: TokenBalancesControllerMessenger;\n state?: Partial<TokenBalancesControllerState>;\n};\n\n/**\n * A mapping from account address to chain id to token address to balance.\n */\ntype TokenBalances = Record<Hex, Record<Hex, Record<Hex, Hex>>>;\n\n/**\n * Token balances controller state\n * @property tokenBalances - A mapping from account address to chain id to token address to balance.\n */\nexport type TokenBalancesControllerState = {\n tokenBalances: TokenBalances;\n};\n\nexport type TokenBalancesControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenBalancesControllerState\n>;\n\nexport type TokenBalancesControllerActions =\n TokenBalancesControllerGetStateAction;\n\nexport type AllowedActions = NetworkControllerGetNetworkClientByIdAction;\n\nexport type TokenBalancesControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n TokenBalancesControllerState\n >;\n\nexport type TokenBalancesControllerEvents =\n TokenBalancesControllerStateChangeEvent;\n\nexport type AllowedEvents = TokensControllerStateChangeEvent;\n\nexport type TokenBalancesControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenBalancesControllerActions | AllowedActions,\n TokenBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Get the default TokenBalancesController state.\n *\n * @returns The default TokenBalancesController state.\n */\nexport function getDefaultTokenBalancesState(): TokenBalancesControllerState {\n return {\n tokenBalances: {},\n };\n}\n\n/** The input to start polling for the {@link TokenBalancesController} */\nexport type TokenBalancesPollingInput = {\n networkClientId: NetworkClientId;\n tokensPerAccount: Record<Hex, Hex[]>;\n};\n\n/**\n * Controller that passively polls on a set interval token balances\n * for tokens stored in the TokensController\n */\nexport class TokenBalancesController extends StaticIntervalPollingController<TokenBalancesPollingInput>()<\n typeof controllerName,\n TokenBalancesControllerState,\n TokenBalancesControllerMessenger\n> {\n /**\n * Construct a Token Balances Controller.\n *\n * @param options - The controller options.\n * @param options.interval - Polling interval used to fetch new token balances.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller restricted messenger.\n */\n constructor({\n interval = DEFAULT_INTERVAL,\n messenger,\n state = {},\n }: TokenBalancesControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultTokenBalancesState(),\n ...state,\n },\n });\n\n this.setIntervalLength(interval);\n }\n\n /**\n * Polls for erc20 token balances.\n * @param input - The input for the poll.\n * @param input.networkClientId - The network client id to poll with.\n * @param input.tokensPerAccount - A mapping from account addresses to token addresses to poll.\n */\n async _executePoll({\n networkClientId,\n tokensPerAccount,\n }: TokenBalancesPollingInput): Promise<void> {\n const networkClient = this.messagingSystem.call(\n `NetworkController:getNetworkClientById`,\n networkClientId,\n );\n\n const { chainId } = networkClient.configuration;\n const provider = new Web3Provider(networkClient.provider);\n\n const accountTokenPairs = Object.entries(tokensPerAccount).flatMap(\n ([accountAddress, tokenAddresses]) =>\n tokenAddresses.map((tokenAddress) => ({\n accountAddress: accountAddress as Hex,\n tokenAddress,\n })),\n );\n\n const calls = accountTokenPairs.map(({ accountAddress, tokenAddress }) => ({\n contract: new Contract(tokenAddress, abiERC20, provider),\n functionSignature: 'balanceOf(address)',\n arguments: [accountAddress],\n }));\n\n const results = await multicallOrFallback(calls, chainId, provider);\n\n this.update((state) => {\n for (let i = 0; i < results.length; i++) {\n const { success, value } = results[i];\n\n if (success) {\n const { accountAddress, tokenAddress } = accountTokenPairs[i];\n ((state.tokenBalances[accountAddress] ??= {})[chainId] ??= {})[\n tokenAddress\n ] = toHex(value as BN);\n }\n }\n });\n }\n}\n\nexport default TokenBalancesController;\n"]}