@metamask/assets-controllers 20.0.0 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -1
- package/dist/AccountTrackerController.d.ts +28 -7
- package/dist/AccountTrackerController.d.ts.map +1 -1
- package/dist/AccountTrackerController.js +104 -30
- package/dist/AccountTrackerController.js.map +1 -1
- package/dist/AssetsContractController.d.ts +3 -3
- package/dist/AssetsContractController.d.ts.map +1 -1
- package/dist/AssetsContractController.js +9 -3
- package/dist/AssetsContractController.js.map +1 -1
- package/dist/CurrencyRateController.d.ts +2 -2
- package/dist/CurrencyRateController.d.ts.map +1 -1
- package/dist/CurrencyRateController.js +1 -1
- package/dist/CurrencyRateController.js.map +1 -1
- package/dist/NftController.d.ts +73 -1
- package/dist/NftController.d.ts.map +1 -1
- package/dist/NftController.js +26 -9
- package/dist/NftController.js.map +1 -1
- package/dist/NftDetectionController.d.ts +7 -4
- package/dist/NftDetectionController.d.ts.map +1 -1
- package/dist/NftDetectionController.js +26 -14
- package/dist/NftDetectionController.js.map +1 -1
- package/dist/Standards/ERC20Standard.d.ts.map +1 -1
- package/dist/Standards/ERC20Standard.js +4 -0
- package/dist/Standards/ERC20Standard.js.map +1 -1
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts +11 -10
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts.map +1 -1
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js +106 -85
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js.map +1 -1
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.d.ts.map +1 -1
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.js +2 -0
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.js.map +1 -1
- package/dist/Standards/standards-types.d.ts.map +1 -1
- package/dist/Standards/standards-types.js.map +1 -1
- package/dist/TokenDetectionController.d.ts +2 -2
- package/dist/TokenDetectionController.d.ts.map +1 -1
- package/dist/TokenDetectionController.js +1 -1
- package/dist/TokenDetectionController.js.map +1 -1
- package/dist/TokenListController.d.ts +2 -2
- package/dist/TokenListController.d.ts.map +1 -1
- package/dist/TokenListController.js +3 -15
- package/dist/TokenListController.js.map +1 -1
- package/dist/TokenRatesController.d.ts +9 -75
- package/dist/TokenRatesController.d.ts.map +1 -1
- package/dist/TokenRatesController.js +180 -203
- package/dist/TokenRatesController.js.map +1 -1
- package/dist/TokensController.d.ts +6 -8
- package/dist/TokensController.d.ts.map +1 -1
- package/dist/TokensController.js +70 -21
- package/dist/TokensController.js.map +1 -1
- package/dist/assetsUtil.d.ts +59 -9
- package/dist/assetsUtil.d.ts.map +1 -1
- package/dist/assetsUtil.js +138 -27
- package/dist/assetsUtil.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/token-prices-service/abstract-token-prices-service.d.ts +62 -0
- package/dist/token-prices-service/abstract-token-prices-service.d.ts.map +1 -0
- package/dist/token-prices-service/abstract-token-prices-service.js +3 -0
- package/dist/token-prices-service/abstract-token-prices-service.js.map +1 -0
- package/dist/token-prices-service/codefi-v2.d.ts +80 -0
- package/dist/token-prices-service/codefi-v2.d.ts.map +1 -0
- package/dist/token-prices-service/codefi-v2.js +327 -0
- package/dist/token-prices-service/codefi-v2.js.map +1 -0
- package/dist/token-prices-service/index.d.ts +3 -0
- package/dist/token-prices-service/index.d.ts.map +1 -0
- package/dist/token-prices-service/index.js +6 -0
- package/dist/token-prices-service/index.js.map +1 -0
- package/dist/token-service.d.ts.map +1 -1
- package/dist/token-service.js +1 -1
- package/dist/token-service.js.map +1 -1
- package/package.json +6 -3
|
@@ -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 handleFetch,\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 { PollingControllerV1 } from '@metamask/polling-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport { fetchExchangeRate as fetchNativeExchangeRate } from './crypto-compare';\nimport type { TokensState } from './TokensController';\n\n/**\n * @type CoinGeckoResponse\n *\n * CoinGecko API response representation\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 CoinGeckoResponse {\n [address: string]: {\n [currency: string]: number;\n };\n}\n/**\n * @type CoinGeckoPlatform\n *\n * CoinGecko supported platform API representation\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 CoinGeckoPlatform {\n id: string;\n chain_identifier: null | number;\n name: string;\n shortname: string;\n}\n\n/**\n * @type Token\n *\n * Token representation\n * @property address - Hex address of the token contract\n * @property decimals - Number of decimals the token uses\n * @property symbol - Symbol of the token\n * @property image - Image of the token, url or bit32 image\n */\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\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 SupportedChainsCache {\n timestamp: number;\n data: CoinGeckoPlatform[] | null;\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 SupportedVsCurrenciesCache {\n timestamp: number;\n data: string[];\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\nconst CoinGeckoApi = {\n BASE_URL: 'https://api.coingecko.com/api/v3',\n getTokenPriceURL(chainSlug: string, query: string) {\n return `${this.BASE_URL}/simple/token_price/${chainSlug}?${query}`;\n },\n getPlatformsURL() {\n return `${this.BASE_URL}/asset_platforms`;\n },\n getSupportedVsCurrencies() {\n return `${this.BASE_URL}/simple/supported_vs_currencies`;\n },\n};\n\n/**\n * Finds the chain slug in the data array given a chainId.\n *\n * @param chainId - The current chain ID.\n * @param data - A list platforms supported by the CoinGecko API.\n * @returns The CoinGecko slug for the given chain ID, or `null` if the slug was not found.\n */\nfunction findChainSlug(\n chainId: Hex,\n data: CoinGeckoPlatform[] | null,\n): string | null {\n if (!data) {\n return null;\n }\n const chain =\n data.find(\n ({ chain_identifier }) =>\n chain_identifier !== null && toHex(chain_identifier) === chainId,\n ) ?? null;\n return chain?.id || null;\n}\n\n/**\n * Controller that passively polls on a set interval for token-to-fiat exchange rates\n * for tokens stored in the TokensController\n */\nexport class TokenRatesController extends PollingControllerV1<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n private tokenList: Token[] = [];\n\n private supportedChains: SupportedChainsCache = {\n timestamp: 0,\n data: null,\n };\n\n private supportedVsCurrencies: SupportedVsCurrenciesCache = {\n timestamp: 0,\n data: [],\n };\n\n #pollState = PollState.Inactive;\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 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 }: {\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 },\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\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 * Fetches a pairs of token address and native currency.\n *\n * @param chainSlug - The chain string identifier.\n * @param vsCurrency - The currency used to generate pairs against the tokens.\n * @param tokenAddresses - The addresses for the token contracts.\n * @returns The exchange rates for the given pairs.\n */\n async fetchExchangeRate(\n chainSlug: string,\n vsCurrency: string,\n tokenAddresses: string[] = this.tokenList.map((token) => token.address),\n ): Promise<CoinGeckoResponse> {\n const tokenPairs = tokenAddresses.join(',');\n const query = `contract_addresses=${tokenPairs}&vs_currencies=${vsCurrency.toLowerCase()}`;\n return handleFetch(CoinGeckoApi.getTokenPriceURL(chainSlug, query));\n }\n\n /**\n * Checks if the current native currency is a supported vs currency to use\n * to query for token exchange rates.\n *\n * @param nativeCurrency - The native currency to check.\n * @returns A boolean indicating whether it's a supported vsCurrency.\n */\n private async checkIsSupportedVsCurrency(nativeCurrency: string) {\n const { threshold } = this.config;\n const { timestamp, data } = this.supportedVsCurrencies;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const currencies = await handleFetch(\n CoinGeckoApi.getSupportedVsCurrencies(),\n );\n this.supportedVsCurrencies = {\n data: currencies,\n timestamp: Date.now(),\n };\n return currencies.includes(nativeCurrency.toLowerCase());\n }\n\n return data.includes(nativeCurrency.toLowerCase());\n }\n\n /**\n * Gets the slug from cached supported platforms CoinGecko API response for the chain ID.\n * If cached supported platforms response is stale, fetches and updates it.\n *\n * @param chainId - The chain ID.\n * @returns The CoinGecko slug for the chain ID.\n */\n async getChainSlug(\n chainId: Hex = this.config.chainId,\n ): Promise<string | null> {\n const { threshold } = this.config;\n const { data, timestamp } = this.supportedChains;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const platforms = await handleFetch(CoinGeckoApi.getPlatformsURL());\n this.supportedChains = {\n data: platforms,\n timestamp: Date.now(),\n };\n return findChainSlug(chainId, platforms);\n }\n\n return findChainSlug(chainId, data);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n if (this.tokenList.length === 0 || this.disabled) {\n return;\n }\n\n const { chainId, nativeCurrency } = this.config;\n const tokenAddresses = this.tokenList.map((token) => token.address);\n await this.updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n tokenAddresses,\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.tokenAddresses - The addresses for the token contracts.\n */\n async updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n tokenAddresses,\n }: {\n chainId: Hex;\n nativeCurrency: string;\n tokenAddresses: string[];\n }) {\n if (!tokenAddresses.length) {\n return;\n }\n const chainSlug = await this.getChainSlug(chainId);\n\n let newContractExchangeRates: ContractExchangeRates = {};\n if (!chainSlug) {\n tokenAddresses.forEach((tokenAddress) => {\n const address = toChecksumHexAddress(tokenAddress);\n newContractExchangeRates[address] = undefined;\n });\n } else {\n newContractExchangeRates = await this.fetchAndMapExchangeRates(\n nativeCurrency,\n chainSlug,\n tokenAddresses,\n );\n }\n\n const existingContractExchangeRatesForChainId =\n this.state.contractExchangeRatesByChainId[chainId] ?? {};\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 * Checks if the active network's native currency is supported by the coingecko API.\n * If supported, it fetches and maps contractExchange rates to a format to be consumed by the UI.\n * If not supported, it fetches contractExchange rates and maps them from token/fallback-currency\n * to token/nativeCurrency.\n *\n * @param nativeCurrency - The native currency ticker against which to fetch exchange rates\n * @param chainSlug - The unique slug used to id the chain by the coingecko api\n * should be used to query token exchange rates.\n * @param tokenAddresses - The addresses for the token contracts against which to fetch exchange rates.\n * @returns An object with conversion rates for each token\n * related to the network's native currency.\n */\n async fetchAndMapExchangeRates(\n nativeCurrency: string,\n chainSlug: string,\n tokenAddresses: string[] = this.tokenList.map((token) => token.address),\n ): Promise<ContractExchangeRates> {\n const contractExchangeRates: ContractExchangeRates = {};\n\n // check if native currency is supported as a vs_currency by the API\n const nativeCurrencySupported = await this.checkIsSupportedVsCurrency(\n nativeCurrency,\n );\n\n if (nativeCurrencySupported) {\n // If it is we can do a simple fetch against the CoinGecko API\n const prices = await this.fetchExchangeRate(\n chainSlug,\n nativeCurrency,\n tokenAddresses,\n );\n tokenAddresses.forEach((tokenAddress) => {\n const price = prices[tokenAddress.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(tokenAddress)] = price\n ? price[nativeCurrency.toLowerCase()]\n : 0;\n });\n } else {\n // if native currency is not supported we need to use a fallback vsCurrency, get the exchange rates\n // in token/fallback-currency format and convert them to expected token/nativeCurrency format.\n let tokenExchangeRates;\n let vsCurrencyToNativeCurrencyConversionRate = 0;\n try {\n [\n tokenExchangeRates,\n { conversionRate: vsCurrencyToNativeCurrencyConversionRate },\n ] = await Promise.all([\n this.fetchExchangeRate(\n chainSlug,\n FALL_BACK_VS_CURRENCY,\n tokenAddresses,\n ),\n fetchNativeExchangeRate(nativeCurrency, FALL_BACK_VS_CURRENCY, false),\n ]);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return {};\n }\n throw error;\n }\n\n for (const [tokenAddress, conversion] of Object.entries(\n tokenExchangeRates,\n )) {\n const tokenToVsCurrencyConversionRate =\n conversion[FALL_BACK_VS_CURRENCY.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(tokenAddress)] =\n tokenToVsCurrencyConversionRate *\n vsCurrencyToNativeCurrencyConversionRate;\n }\n }\n\n return contractExchangeRates;\n }\n\n /**\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: string[] },\n ): Promise<void> {\n const networkClient = this.getNetworkClientById(networkClientId);\n await this.updateExchangeRatesByChainId({\n chainId: networkClient.configuration.chainId,\n nativeCurrency: networkClient.configuration.ticker,\n tokenAddresses: options.tokenAddresses,\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 } 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\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 * The maximum number of token addresses that should be sent to the Price API in\n * a single request.\n */\nconst TOKEN_PRICES_BATCH_SIZE = 100;\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
|
/**
|
|
@@ -103,7 +103,6 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
103
103
|
* Name of this controller used during composition
|
|
104
104
|
*/
|
|
105
105
|
name: string;
|
|
106
|
-
private readonly getERC20TokenName;
|
|
107
106
|
private readonly getNetworkClientById;
|
|
108
107
|
/**
|
|
109
108
|
* Creates a TokensController instance.
|
|
@@ -111,20 +110,18 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
111
110
|
* @param options - The controller options.
|
|
112
111
|
* @param options.chainId - The chain ID of the current network.
|
|
113
112
|
* @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.
|
|
114
|
-
* @param options.
|
|
113
|
+
* @param options.onNetworkDidChange - Allows subscribing to network controller networkDidChange events.
|
|
115
114
|
* @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.
|
|
116
|
-
* @param options.getERC20TokenName - Gets the ERC-20 token name.
|
|
117
115
|
* @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.
|
|
118
116
|
* @param options.config - Initial options used to configure this controller.
|
|
119
117
|
* @param options.state - Initial state to set on this controller.
|
|
120
118
|
* @param options.messenger - The controller messenger.
|
|
121
119
|
*/
|
|
122
|
-
constructor({ chainId: initialChainId, onPreferencesStateChange,
|
|
120
|
+
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkDidChange, onTokenListStateChange, getNetworkClientById, config, state, messenger, }: {
|
|
123
121
|
chainId: Hex;
|
|
124
122
|
onPreferencesStateChange: (listener: (preferencesState: PreferencesState) => void) => void;
|
|
125
|
-
|
|
123
|
+
onNetworkDidChange: (listener: (networkState: NetworkState) => void) => void;
|
|
126
124
|
onTokenListStateChange: (listener: (tokenListState: TokenListState) => void) => void;
|
|
127
|
-
getERC20TokenName: AssetsContractController['getERC20TokenName'];
|
|
128
125
|
getNetworkClientById: NetworkController['getNetworkClientById'];
|
|
129
126
|
config?: Partial<TokensConfig>;
|
|
130
127
|
state?: Partial<TokensState>;
|
|
@@ -201,6 +198,7 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
201
198
|
* interface.
|
|
202
199
|
*/
|
|
203
200
|
_detectIsERC721(tokenAddress: string, networkClientId?: NetworkClientId): Promise<any>;
|
|
201
|
+
_getProvider(networkClientId?: NetworkClientId): Web3Provider;
|
|
204
202
|
_createEthersContract(tokenAddress: string, abi: string, networkClientId?: NetworkClientId): Contract;
|
|
205
203
|
_generateRandomId(): string;
|
|
206
204
|
/**
|
|
@@ -212,7 +210,7 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
212
210
|
* @param options.type - The asset type.
|
|
213
211
|
* @param options.interactingAddress - The address of the account that is requesting to watch the asset.
|
|
214
212
|
* @param options.networkClientId - Network Client ID.
|
|
215
|
-
* @returns
|
|
213
|
+
* @returns A promise that resolves if the asset was watched successfully, and rejects otherwise.
|
|
216
214
|
*/
|
|
217
215
|
watchAsset({ asset, type, interactingAddress, networkClientId, }: {
|
|
218
216
|
asset: Token;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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"}
|
package/dist/TokensController.js
CHANGED
|
@@ -19,10 +19,13 @@ const base_controller_1 = require("@metamask/base-controller");
|
|
|
19
19
|
const contract_metadata_1 = __importDefault(require("@metamask/contract-metadata"));
|
|
20
20
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
21
21
|
const metamask_eth_abis_1 = require("@metamask/metamask-eth-abis");
|
|
22
|
+
const rpc_errors_1 = require("@metamask/rpc-errors");
|
|
22
23
|
const async_mutex_1 = require("async-mutex");
|
|
23
24
|
const events_1 = require("events");
|
|
24
25
|
const uuid_1 = require("uuid");
|
|
25
26
|
const assetsUtil_1 = require("./assetsUtil");
|
|
27
|
+
const ERC20Standard_1 = require("./Standards/ERC20Standard");
|
|
28
|
+
const ERC1155Standard_1 = require("./Standards/NftStandards/ERC1155/ERC1155Standard");
|
|
26
29
|
const token_service_1 = require("./token-service");
|
|
27
30
|
/**
|
|
28
31
|
* The name of the {@link TokensController}.
|
|
@@ -38,15 +41,14 @@ class TokensController extends base_controller_1.BaseControllerV1 {
|
|
|
38
41
|
* @param options - The controller options.
|
|
39
42
|
* @param options.chainId - The chain ID of the current network.
|
|
40
43
|
* @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.
|
|
41
|
-
* @param options.
|
|
44
|
+
* @param options.onNetworkDidChange - Allows subscribing to network controller networkDidChange events.
|
|
42
45
|
* @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.
|
|
43
|
-
* @param options.getERC20TokenName - Gets the ERC-20 token name.
|
|
44
46
|
* @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.
|
|
45
47
|
* @param options.config - Initial options used to configure this controller.
|
|
46
48
|
* @param options.state - Initial state to set on this controller.
|
|
47
49
|
* @param options.messenger - The controller messenger.
|
|
48
50
|
*/
|
|
49
|
-
constructor({ chainId: initialChainId, onPreferencesStateChange,
|
|
51
|
+
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkDidChange, onTokenListStateChange, getNetworkClientById, config, state, messenger, }) {
|
|
50
52
|
super(config, state);
|
|
51
53
|
this.mutex = new async_mutex_1.Mutex();
|
|
52
54
|
/**
|
|
@@ -61,7 +63,6 @@ class TokensController extends base_controller_1.BaseControllerV1 {
|
|
|
61
63
|
this.defaultState = Object.assign({ tokens: [], ignoredTokens: [], detectedTokens: [], allTokens: {}, allIgnoredTokens: {}, allDetectedTokens: {} }, state);
|
|
62
64
|
this.initialize();
|
|
63
65
|
this.abortController = new AbortController();
|
|
64
|
-
this.getERC20TokenName = getERC20TokenName;
|
|
65
66
|
this.getNetworkClientById = getNetworkClientById;
|
|
66
67
|
this.messagingSystem = messenger;
|
|
67
68
|
onPreferencesStateChange(({ selectedAddress }) => {
|
|
@@ -75,7 +76,7 @@ class TokensController extends base_controller_1.BaseControllerV1 {
|
|
|
75
76
|
detectedTokens: ((_c = allDetectedTokens[chainId]) === null || _c === void 0 ? void 0 : _c[selectedAddress]) || [],
|
|
76
77
|
});
|
|
77
78
|
});
|
|
78
|
-
|
|
79
|
+
onNetworkDidChange(({ providerConfig }) => {
|
|
79
80
|
var _a, _b, _c;
|
|
80
81
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
81
82
|
const { selectedAddress } = this.config;
|
|
@@ -429,6 +430,8 @@ class TokensController extends base_controller_1.BaseControllerV1 {
|
|
|
429
430
|
const tokenContract = this._createEthersContract(tokenAddress, metamask_eth_abis_1.abiERC721, networkClientId);
|
|
430
431
|
try {
|
|
431
432
|
return yield tokenContract.supportsInterface(controller_utils_1.ERC721_INTERFACE_ID);
|
|
433
|
+
// TODO: Replace `any` with type
|
|
434
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
432
435
|
}
|
|
433
436
|
catch (error) {
|
|
434
437
|
// currently we see a variety of errors across different networks when
|
|
@@ -439,12 +442,14 @@ class TokensController extends base_controller_1.BaseControllerV1 {
|
|
|
439
442
|
}
|
|
440
443
|
});
|
|
441
444
|
}
|
|
442
|
-
|
|
445
|
+
_getProvider(networkClientId) {
|
|
443
446
|
var _a;
|
|
444
|
-
|
|
447
|
+
return new providers_1.Web3Provider(networkClientId
|
|
445
448
|
? this.getNetworkClientById(networkClientId).provider
|
|
446
|
-
: (_a = this.config) === null || _a === void 0 ? void 0 : _a.provider;
|
|
447
|
-
|
|
449
|
+
: (_a = this.config) === null || _a === void 0 ? void 0 : _a.provider);
|
|
450
|
+
}
|
|
451
|
+
_createEthersContract(tokenAddress, abi, networkClientId) {
|
|
452
|
+
const web3provider = this._getProvider(networkClientId);
|
|
448
453
|
const tokenContract = new contracts_1.Contract(tokenAddress, abi, web3provider);
|
|
449
454
|
return tokenContract;
|
|
450
455
|
}
|
|
@@ -460,31 +465,75 @@ class TokensController extends base_controller_1.BaseControllerV1 {
|
|
|
460
465
|
* @param options.type - The asset type.
|
|
461
466
|
* @param options.interactingAddress - The address of the account that is requesting to watch the asset.
|
|
462
467
|
* @param options.networkClientId - Network Client ID.
|
|
463
|
-
* @returns
|
|
468
|
+
* @returns A promise that resolves if the asset was watched successfully, and rejects otherwise.
|
|
464
469
|
*/
|
|
465
470
|
watchAsset({ asset, type, interactingAddress, networkClientId, }) {
|
|
466
471
|
return __awaiter(this, void 0, void 0, function* () {
|
|
467
472
|
if (type !== controller_utils_1.ERC20) {
|
|
468
473
|
throw new Error(`Asset of type ${type} not supported`);
|
|
469
474
|
}
|
|
470
|
-
|
|
475
|
+
if (!asset.address) {
|
|
476
|
+
throw rpc_errors_1.rpcErrors.invalidParams('Address must be specified');
|
|
477
|
+
}
|
|
478
|
+
if (!(0, controller_utils_1.isValidHexAddress)(asset.address)) {
|
|
479
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid address "${asset.address}"`);
|
|
480
|
+
}
|
|
481
|
+
// Validate contract
|
|
482
|
+
if (yield this._detectIsERC721(asset.address, networkClientId)) {
|
|
483
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Contract ${asset.address} must match type ${type}, but was detected as ${controller_utils_1.ERC721}`);
|
|
484
|
+
}
|
|
485
|
+
const provider = this._getProvider(networkClientId);
|
|
486
|
+
const isErc1155 = yield (0, controller_utils_1.safelyExecute)(() => new ERC1155Standard_1.ERC1155Standard(provider).contractSupportsBase1155Interface(asset.address));
|
|
487
|
+
if (isErc1155) {
|
|
488
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Contract ${asset.address} must match type ${type}, but was detected as ${controller_utils_1.ERC1155}`);
|
|
489
|
+
}
|
|
490
|
+
const erc20 = new ERC20Standard_1.ERC20Standard(provider);
|
|
491
|
+
const [contractName, contractSymbol, contractDecimals] = yield Promise.all([
|
|
492
|
+
(0, controller_utils_1.safelyExecute)(() => erc20.getTokenName(asset.address)),
|
|
493
|
+
(0, controller_utils_1.safelyExecute)(() => erc20.getTokenSymbol(asset.address)),
|
|
494
|
+
(0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { return erc20.getTokenDecimals(asset.address); })),
|
|
495
|
+
]);
|
|
496
|
+
asset.name = contractName;
|
|
497
|
+
// Validate symbol
|
|
498
|
+
if (!asset.symbol && !contractSymbol) {
|
|
499
|
+
throw rpc_errors_1.rpcErrors.invalidParams('A symbol is required, but was not found in either the request or contract');
|
|
500
|
+
}
|
|
501
|
+
if (contractSymbol !== undefined &&
|
|
502
|
+
asset.symbol !== undefined &&
|
|
503
|
+
asset.symbol.toUpperCase() !== contractSymbol.toUpperCase()) {
|
|
504
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`The symbol in the request (${asset.symbol}) does not match the symbol in the contract (${contractSymbol})`);
|
|
505
|
+
}
|
|
506
|
+
asset.symbol = contractSymbol !== null && contractSymbol !== void 0 ? contractSymbol : asset.symbol;
|
|
507
|
+
if (typeof asset.symbol !== 'string') {
|
|
508
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid symbol: not a string`);
|
|
509
|
+
}
|
|
510
|
+
if (asset.symbol.length > 11) {
|
|
511
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid symbol "${asset.symbol}": longer than 11 characters`);
|
|
512
|
+
}
|
|
513
|
+
// Validate decimals
|
|
514
|
+
if (asset.decimals === undefined && contractDecimals === undefined) {
|
|
515
|
+
throw rpc_errors_1.rpcErrors.invalidParams('Decimals are required, but were not found in either the request or contract');
|
|
516
|
+
}
|
|
517
|
+
if (contractDecimals !== undefined &&
|
|
518
|
+
asset.decimals !== undefined &&
|
|
519
|
+
String(asset.decimals) !== contractDecimals) {
|
|
520
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`The decimals in the request (${asset.decimals}) do not match the decimals in the contract (${contractDecimals})`);
|
|
521
|
+
}
|
|
522
|
+
const decimalsStr = contractDecimals !== null && contractDecimals !== void 0 ? contractDecimals : asset.decimals;
|
|
523
|
+
const decimalsNum = parseInt(decimalsStr, 10);
|
|
524
|
+
if (!Number.isInteger(decimalsNum) || decimalsNum > 36 || decimalsNum < 0) {
|
|
525
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid decimals "${decimalsStr}": must be an integer 0 <= 36`);
|
|
526
|
+
}
|
|
527
|
+
asset.decimals = decimalsNum;
|
|
471
528
|
const suggestedAssetMeta = {
|
|
472
529
|
asset,
|
|
473
530
|
id: this._generateRandomId(),
|
|
474
531
|
time: Date.now(),
|
|
475
532
|
type,
|
|
476
|
-
interactingAddress: interactingAddress || selectedAddress,
|
|
533
|
+
interactingAddress: interactingAddress || this.config.selectedAddress,
|
|
477
534
|
};
|
|
478
|
-
(0, assetsUtil_1.validateTokenToWatch)(asset);
|
|
479
535
|
yield this._requestApproval(suggestedAssetMeta);
|
|
480
|
-
|
|
481
|
-
try {
|
|
482
|
-
name = yield this.getERC20TokenName(asset.address, networkClientId);
|
|
483
|
-
}
|
|
484
|
-
catch (error) {
|
|
485
|
-
name = undefined;
|
|
486
|
-
}
|
|
487
|
-
const { address, symbol, decimals, image } = asset;
|
|
536
|
+
const { address, symbol, decimals, name, image } = asset;
|
|
488
537
|
yield this.addToken({
|
|
489
538
|
address,
|
|
490
539
|
symbol,
|