@metamask/assets-controllers 12.0.0 → 13.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 +27 -3
- package/dist/NftDetectionController.d.ts +1 -2
- package/dist/NftDetectionController.d.ts.map +1 -1
- package/dist/NftDetectionController.js.map +1 -1
- package/dist/TokensController.d.ts +33 -18
- package/dist/TokensController.d.ts.map +1 -1
- package/dist/TokensController.js +53 -29
- package/dist/TokensController.js.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [13.0.0]
|
|
10
|
+
### Changed
|
|
11
|
+
- **BREAKING**: `TokensController` now expects `getNetworkClientById` in constructor options ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
12
|
+
- **BREAKING**: `TokensController.addToken` now accepts a single options object ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
13
|
+
```
|
|
14
|
+
{
|
|
15
|
+
address: string;
|
|
16
|
+
symbol: string;
|
|
17
|
+
decimals: number;
|
|
18
|
+
name?: string;
|
|
19
|
+
image?: string;
|
|
20
|
+
interactingAddress?: string;
|
|
21
|
+
networkClientId?: NetworkClientId;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
- **BREAKING**: Bump peer dependency on `@metamask/network-controller` to ^13.0.0 ([#1633](https://github.com/MetaMask/core/pull/1633))
|
|
25
|
+
- **CHANGED**: `TokensController.addToken` will use the chain ID value derived from state for `networkClientId` if provided ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
26
|
+
- **CHANGED**: `TokensController.addTokens` now accepts an optional `networkClientId` as the last parameter ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
27
|
+
- **CHANGED**: `TokensController.addTokens` will use the chain ID value derived from state for `networkClientId` if provided ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
28
|
+
- **CHANGED**: `TokensController.watchAsset` options now accepts optional `networkClientId` which is used to get the ERC-20 token name if provided ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
29
|
+
- Bump dependency on `@metamask/controller-utils` to ^5.0.0 ([#1633](https://github.com/MetaMask/core/pull/1633))
|
|
30
|
+
- Bump dependency on `@metamask/preferences-controller` to ^4.4.1 ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
31
|
+
|
|
9
32
|
## [12.0.0]
|
|
10
33
|
### Added
|
|
11
34
|
- Add `AssetsContractController` methods `getProvider`, `getChainId`, `getERC721Standard`, and `getERC1155Standard` ([#1638](https://github.com/MetaMask/core/pull/1638))
|
|
@@ -78,7 +101,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
78
101
|
- The `getERC20TokenName` method is used to get the token name for tokens added via `wallet_watchAsset`
|
|
79
102
|
- The `onTokenListStateChange` method is used to trigger a name update when the token list changes. On each change, token names are copied from the token list if they're missing from token controller state.
|
|
80
103
|
- **BREAKING:** The signature of the tokens controller method `addToken` has changed
|
|
81
|
-
- The fourth and fifth positional parameters (`image` and `interactingAddress`) have been replaced by an `options` object
|
|
104
|
+
- The fourth and fifth positional parameters (`image` and `interactingAddress`) have been replaced by an `options` object
|
|
82
105
|
- The new options parameter includes the `image` and `interactingAddress` properties, and a new `name` property
|
|
83
106
|
- The token detection controller now sets the token name when new tokens are detected ([#1127](https://github.com/MetaMask/core/pull/1127))
|
|
84
107
|
- The `Token` type now includes an optional `name` field ([#1127](https://github.com/MetaMask/core/pull/1127))
|
|
@@ -157,7 +180,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
157
180
|
- **BREAKING:** Remove the `networkType` configuration option from the NFT detection controller, NFT controller, and tokens controller ([#1360](https://github.com/MetaMask/core/pull/1360), [#1359](https://github.com/MetaMask/core/pull/1359))
|
|
158
181
|
- **BREAKING:** Remove the `SuggestedAssetMeta` and `SuggestedAssetMetaBase` types from the token controller ([#1268](https://github.com/MetaMask/core/pull/1268))
|
|
159
182
|
- **BREAKING:** Remove the `acceptWatchAsset` and `rejectWatchAsset` methods from the token controller ([#1268](https://github.com/MetaMask/core/pull/1268))
|
|
160
|
-
- Suggested assets can be accepted or rejected using the approval controller instead
|
|
183
|
+
- Suggested assets can be accepted or rejected using the approval controller instead
|
|
161
184
|
|
|
162
185
|
## [7.0.0]
|
|
163
186
|
### Changed
|
|
@@ -248,7 +271,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
248
271
|
### Changed
|
|
249
272
|
- Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/core/pull/845))
|
|
250
273
|
|
|
251
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@
|
|
274
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@13.0.0...HEAD
|
|
275
|
+
[13.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@12.0.0...@metamask/assets-controllers@13.0.0
|
|
252
276
|
[12.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@11.1.0...@metamask/assets-controllers@12.0.0
|
|
253
277
|
[11.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@11.0.1...@metamask/assets-controllers@11.1.0
|
|
254
278
|
[11.0.1]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@11.0.0...@metamask/assets-controllers@11.0.1
|
|
@@ -105,9 +105,8 @@ export interface ApiNftCreator {
|
|
|
105
105
|
*
|
|
106
106
|
* NftDetection configuration
|
|
107
107
|
* @property interval - Polling interval used to fetch new token rates
|
|
108
|
-
* @property
|
|
108
|
+
* @property chainId - Current chain ID
|
|
109
109
|
* @property selectedAddress - Vault selected address
|
|
110
|
-
* @property tokens - List of tokens associated with the active vault
|
|
111
110
|
*/
|
|
112
111
|
export interface NftDetectionConfig extends BaseConfig {
|
|
113
112
|
interval: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NftDetectionController.d.ts","sourceRoot":"","sources":["../src/NftDetectionController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAO3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAG3C,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAe,MAAM,iBAAiB,CAAC;AAI5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC;CACH;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED
|
|
1
|
+
{"version":3,"file":"NftDetectionController.d.ts","sourceRoot":"","sources":["../src/NftDetectionController.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NftDetectionController.js","sourceRoot":"","sources":["../src/NftDetectionController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseConfig, BaseState } from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n OPENSEA_PROXY_URL,\n fetchWithErrorHandling,\n toChecksumHexAddress,\n ChainId,\n} from '@metamask/controller-utils';\nimport type { NetworkState } from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport { Source } from './constants';\nimport type { NftController, NftState, NftMetadata } from './NftController';\n\nconst DEFAULT_INTERVAL = 180000;\n\n/**\n * @type ApiNft\n *\n * NFT object coming from OpenSea api\n * @property token_id - The NFT identifier\n * @property num_sales - Number of sales\n * @property background_color - The background color to be displayed with the item\n * @property image_url - URI of an image associated with this NFT\n * @property image_preview_url - URI of a smaller image associated with this NFT\n * @property image_thumbnail_url - URI of a thumbnail image associated with this NFT\n * @property image_original_url - URI of the original image associated with this NFT\n * @property animation_url - URI of a animation associated with this NFT\n * @property animation_original_url - URI of the original animation associated with this NFT\n * @property name - The NFT name\n * @property description - The NFT description\n * @property external_link - External link containing additional information\n * @property assetContract - The NFT contract information object\n * @property creator - The NFT owner information object\n * @property lastSale - When this item was last sold\n */\nexport interface ApiNft {\n token_id: string;\n num_sales: number | null;\n background_color: string | null;\n image_url: string | null;\n image_preview_url: string | null;\n image_thumbnail_url: string | null;\n image_original_url: string | null;\n animation_url: string | null;\n animation_original_url: string | null;\n name: string | null;\n description: string | null;\n external_link: string | null;\n asset_contract: ApiNftContract;\n creator: ApiNftCreator;\n last_sale: ApiNftLastSale | null;\n}\n\n/**\n * @type ApiNftContract\n *\n * NFT contract object coming from OpenSea api\n * @property address - Address of the NFT contract\n * @property asset_contract_type - The NFT type, it could be `semi-fungible` or `non-fungible`\n * @property created_date - Creation date\n * @property collection - Object containing the contract name and URI of an image associated\n * @property schema_name - The schema followed by the contract, it could be `ERC721` or `ERC1155`\n * @property symbol - The NFT contract symbol\n * @property total_supply - Total supply of NFTs\n * @property description - The NFT contract description\n * @property external_link - External link containing additional information\n */\nexport interface ApiNftContract {\n address: string;\n asset_contract_type: string | null;\n created_date: string | null;\n schema_name: string | null;\n symbol: string | null;\n total_supply: string | null;\n description: string | null;\n external_link: string | null;\n collection: {\n name: string | null;\n image_url?: string | null;\n };\n}\n\n/**\n * @type ApiNftLastSale\n *\n * NFT sale object coming from OpenSea api\n * @property event_timestamp - Object containing a `username`\n * @property total_price - URI of NFT image associated with this owner\n * @property transaction - Object containing transaction_hash and block_hash\n */\nexport interface ApiNftLastSale {\n event_timestamp: string;\n total_price: string;\n transaction: { transaction_hash: string; block_hash: string };\n}\n\n/**\n * @type ApiNftCreator\n *\n * NFT creator object coming from OpenSea api\n * @property user - Object containing a `username`\n * @property profile_img_url - URI of NFT image associated with this owner\n * @property address - The owner address\n */\nexport interface ApiNftCreator {\n user: { username: string };\n profile_img_url: string;\n address: string;\n}\n\n/**\n * @type NftDetectionConfig\n *\n * NftDetection configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property networkType - Network type ID as per net_version\n * @property selectedAddress - Vault selected address\n * @property tokens - List of tokens associated with the active vault\n */\nexport interface NftDetectionConfig extends BaseConfig {\n interval: number;\n chainId: Hex;\n selectedAddress: string;\n}\n\n/**\n * Controller that passively polls on a set interval for NFT auto detection\n */\nexport class NftDetectionController extends BaseController<\n NftDetectionConfig,\n BaseState\n> {\n private intervalId?: ReturnType<typeof setTimeout>;\n\n private getOwnerNftApi({\n address,\n offset,\n }: {\n address: string;\n offset: number;\n }) {\n return `${OPENSEA_PROXY_URL}/assets?owner=${address}&offset=${offset}&limit=50`;\n }\n\n private async getOwnerNfts(address: string) {\n let nftApiResponse: { assets: ApiNft[] };\n let nfts: ApiNft[] = [];\n let offset = 0;\n let pagingFinish = false;\n /* istanbul ignore if */\n do {\n nftApiResponse = await fetchWithErrorHandling({\n url: this.getOwnerNftApi({ address, offset }),\n timeout: 15000,\n });\n\n if (!nftApiResponse) {\n return nfts;\n }\n\n nftApiResponse?.assets?.length !== 0\n ? (nfts = [...nfts, ...nftApiResponse.assets])\n : (pagingFinish = true);\n offset += 50;\n } while (!pagingFinish);\n\n return nfts;\n }\n\n /**\n * Name of this controller used during composition\n */\n override name = 'NftDetectionController';\n\n private readonly getOpenSeaApiKey: () => string | undefined;\n\n private readonly addNft: NftController['addNft'];\n\n private readonly getNftState: () => NftState;\n\n /**\n * Creates an NftDetectionController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onNftsStateChange - Allows subscribing to assets controller state changes.\n * @param options.onPreferencesStateChange - Allows subscribing to preferences controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.getOpenSeaApiKey - Gets the OpenSea API key, if one is set.\n * @param options.addNft - Add an NFT.\n * @param options.getNftState - Gets the current state of the Assets controller.\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 chainId: initialChainId,\n onPreferencesStateChange,\n onNetworkStateChange,\n getOpenSeaApiKey,\n addNft,\n getNftState,\n }: {\n chainId: Hex;\n onNftsStateChange: (listener: (nftsState: NftState) => void) => void;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n getOpenSeaApiKey: () => string | undefined;\n addNft: NftController['addNft'];\n getNftState: () => NftState;\n },\n config?: Partial<NftDetectionConfig>,\n state?: Partial<BaseState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n interval: DEFAULT_INTERVAL,\n chainId: initialChainId,\n selectedAddress: '',\n disabled: true,\n };\n this.initialize();\n this.getNftState = getNftState;\n onPreferencesStateChange(({ selectedAddress, useNftDetection }) => {\n const { selectedAddress: previouslySelectedAddress, disabled } =\n this.config;\n\n if (\n selectedAddress !== previouslySelectedAddress ||\n !useNftDetection !== disabled\n ) {\n this.configure({ selectedAddress, disabled: !useNftDetection });\n }\n\n if (useNftDetection !== undefined) {\n if (useNftDetection) {\n this.start();\n } else {\n this.stop();\n }\n }\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n this.configure({\n chainId: providerConfig.chainId,\n });\n });\n this.getOpenSeaApiKey = getOpenSeaApiKey;\n this.addNft = addNft;\n }\n\n /**\n * Start polling for the currency rate.\n */\n async start() {\n if (!this.isMainnet() || this.disabled) {\n return;\n }\n\n await this.startPolling();\n }\n\n /**\n * Stop polling for the currency rate.\n */\n stop() {\n this.stopPolling();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n *\n * @param interval - An interval on which to poll.\n */\n private async startPolling(interval?: number): Promise<void> {\n interval && this.configure({ interval }, false, false);\n this.stopPolling();\n await this.detectNfts();\n this.intervalId = setInterval(async () => {\n await this.detectNfts();\n }, this.config.interval);\n }\n\n /**\n * Checks whether network is mainnet or not.\n *\n * @returns Whether current network is mainnet.\n */\n isMainnet = (): boolean => this.config.chainId === ChainId.mainnet;\n\n /**\n * Triggers asset ERC721 token auto detection on mainnet. Any newly detected NFTs are\n * added.\n */\n async detectNfts() {\n /* istanbul ignore if */\n if (!this.isMainnet() || this.disabled) {\n return;\n }\n const { selectedAddress, chainId } = this.config;\n\n /* istanbul ignore else */\n if (!selectedAddress) {\n return;\n }\n\n const apiNfts = await this.getOwnerNfts(selectedAddress);\n const addNftPromises = apiNfts.map(async (nft: ApiNft) => {\n const {\n token_id,\n num_sales,\n background_color,\n image_url,\n image_preview_url,\n image_thumbnail_url,\n image_original_url,\n animation_url,\n animation_original_url,\n name,\n description,\n external_link,\n creator,\n asset_contract: { address, schema_name },\n last_sale,\n } = nft;\n\n let ignored;\n /* istanbul ignore else */\n const { ignoredNfts } = this.getNftState();\n if (ignoredNfts.length) {\n ignored = ignoredNfts.find((c) => {\n /* istanbul ignore next */\n return (\n c.address === toChecksumHexAddress(address) &&\n c.tokenId === token_id\n );\n });\n }\n\n /* istanbul ignore else */\n if (!ignored) {\n /* istanbul ignore next */\n const nftMetadata: NftMetadata = Object.assign(\n {},\n { name },\n creator && { creator },\n description && { description },\n image_url && { image: image_url },\n num_sales && { numberOfSales: num_sales },\n background_color && { backgroundColor: background_color },\n image_preview_url && { imagePreview: image_preview_url },\n image_thumbnail_url && { imageThumbnail: image_thumbnail_url },\n image_original_url && { imageOriginal: image_original_url },\n animation_url && { animation: animation_url },\n animation_original_url && {\n animationOriginal: animation_original_url,\n },\n schema_name && { standard: schema_name },\n external_link && { externalLink: external_link },\n last_sale && { lastSale: last_sale },\n );\n\n await this.addNft(\n address,\n token_id,\n nftMetadata,\n {\n userAddress: selectedAddress,\n chainId,\n },\n Source.Detected,\n );\n }\n });\n await Promise.all(addNftPromises);\n }\n}\n\nexport default NftDetectionController;\n"]}
|
|
1
|
+
{"version":3,"file":"NftDetectionController.js","sourceRoot":"","sources":["../src/NftDetectionController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseConfig, BaseState } from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n OPENSEA_PROXY_URL,\n fetchWithErrorHandling,\n toChecksumHexAddress,\n ChainId,\n} from '@metamask/controller-utils';\nimport type { NetworkState } from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport { Source } from './constants';\nimport type { NftController, NftState, NftMetadata } from './NftController';\n\nconst DEFAULT_INTERVAL = 180000;\n\n/**\n * @type ApiNft\n *\n * NFT object coming from OpenSea api\n * @property token_id - The NFT identifier\n * @property num_sales - Number of sales\n * @property background_color - The background color to be displayed with the item\n * @property image_url - URI of an image associated with this NFT\n * @property image_preview_url - URI of a smaller image associated with this NFT\n * @property image_thumbnail_url - URI of a thumbnail image associated with this NFT\n * @property image_original_url - URI of the original image associated with this NFT\n * @property animation_url - URI of a animation associated with this NFT\n * @property animation_original_url - URI of the original animation associated with this NFT\n * @property name - The NFT name\n * @property description - The NFT description\n * @property external_link - External link containing additional information\n * @property assetContract - The NFT contract information object\n * @property creator - The NFT owner information object\n * @property lastSale - When this item was last sold\n */\nexport interface ApiNft {\n token_id: string;\n num_sales: number | null;\n background_color: string | null;\n image_url: string | null;\n image_preview_url: string | null;\n image_thumbnail_url: string | null;\n image_original_url: string | null;\n animation_url: string | null;\n animation_original_url: string | null;\n name: string | null;\n description: string | null;\n external_link: string | null;\n asset_contract: ApiNftContract;\n creator: ApiNftCreator;\n last_sale: ApiNftLastSale | null;\n}\n\n/**\n * @type ApiNftContract\n *\n * NFT contract object coming from OpenSea api\n * @property address - Address of the NFT contract\n * @property asset_contract_type - The NFT type, it could be `semi-fungible` or `non-fungible`\n * @property created_date - Creation date\n * @property collection - Object containing the contract name and URI of an image associated\n * @property schema_name - The schema followed by the contract, it could be `ERC721` or `ERC1155`\n * @property symbol - The NFT contract symbol\n * @property total_supply - Total supply of NFTs\n * @property description - The NFT contract description\n * @property external_link - External link containing additional information\n */\nexport interface ApiNftContract {\n address: string;\n asset_contract_type: string | null;\n created_date: string | null;\n schema_name: string | null;\n symbol: string | null;\n total_supply: string | null;\n description: string | null;\n external_link: string | null;\n collection: {\n name: string | null;\n image_url?: string | null;\n };\n}\n\n/**\n * @type ApiNftLastSale\n *\n * NFT sale object coming from OpenSea api\n * @property event_timestamp - Object containing a `username`\n * @property total_price - URI of NFT image associated with this owner\n * @property transaction - Object containing transaction_hash and block_hash\n */\nexport interface ApiNftLastSale {\n event_timestamp: string;\n total_price: string;\n transaction: { transaction_hash: string; block_hash: string };\n}\n\n/**\n * @type ApiNftCreator\n *\n * NFT creator object coming from OpenSea api\n * @property user - Object containing a `username`\n * @property profile_img_url - URI of NFT image associated with this owner\n * @property address - The owner address\n */\nexport interface ApiNftCreator {\n user: { username: string };\n profile_img_url: string;\n address: string;\n}\n\n/**\n * @type NftDetectionConfig\n *\n * NftDetection configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property chainId - Current chain ID\n * @property selectedAddress - Vault selected address\n */\nexport interface NftDetectionConfig extends BaseConfig {\n interval: number;\n chainId: Hex;\n selectedAddress: string;\n}\n\n/**\n * Controller that passively polls on a set interval for NFT auto detection\n */\nexport class NftDetectionController extends BaseController<\n NftDetectionConfig,\n BaseState\n> {\n private intervalId?: ReturnType<typeof setTimeout>;\n\n private getOwnerNftApi({\n address,\n offset,\n }: {\n address: string;\n offset: number;\n }) {\n return `${OPENSEA_PROXY_URL}/assets?owner=${address}&offset=${offset}&limit=50`;\n }\n\n private async getOwnerNfts(address: string) {\n let nftApiResponse: { assets: ApiNft[] };\n let nfts: ApiNft[] = [];\n let offset = 0;\n let pagingFinish = false;\n /* istanbul ignore if */\n do {\n nftApiResponse = await fetchWithErrorHandling({\n url: this.getOwnerNftApi({ address, offset }),\n timeout: 15000,\n });\n\n if (!nftApiResponse) {\n return nfts;\n }\n\n nftApiResponse?.assets?.length !== 0\n ? (nfts = [...nfts, ...nftApiResponse.assets])\n : (pagingFinish = true);\n offset += 50;\n } while (!pagingFinish);\n\n return nfts;\n }\n\n /**\n * Name of this controller used during composition\n */\n override name = 'NftDetectionController';\n\n private readonly getOpenSeaApiKey: () => string | undefined;\n\n private readonly addNft: NftController['addNft'];\n\n private readonly getNftState: () => NftState;\n\n /**\n * Creates an NftDetectionController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onNftsStateChange - Allows subscribing to assets controller state changes.\n * @param options.onPreferencesStateChange - Allows subscribing to preferences controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.getOpenSeaApiKey - Gets the OpenSea API key, if one is set.\n * @param options.addNft - Add an NFT.\n * @param options.getNftState - Gets the current state of the Assets controller.\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 chainId: initialChainId,\n onPreferencesStateChange,\n onNetworkStateChange,\n getOpenSeaApiKey,\n addNft,\n getNftState,\n }: {\n chainId: Hex;\n onNftsStateChange: (listener: (nftsState: NftState) => void) => void;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n getOpenSeaApiKey: () => string | undefined;\n addNft: NftController['addNft'];\n getNftState: () => NftState;\n },\n config?: Partial<NftDetectionConfig>,\n state?: Partial<BaseState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n interval: DEFAULT_INTERVAL,\n chainId: initialChainId,\n selectedAddress: '',\n disabled: true,\n };\n this.initialize();\n this.getNftState = getNftState;\n onPreferencesStateChange(({ selectedAddress, useNftDetection }) => {\n const { selectedAddress: previouslySelectedAddress, disabled } =\n this.config;\n\n if (\n selectedAddress !== previouslySelectedAddress ||\n !useNftDetection !== disabled\n ) {\n this.configure({ selectedAddress, disabled: !useNftDetection });\n }\n\n if (useNftDetection !== undefined) {\n if (useNftDetection) {\n this.start();\n } else {\n this.stop();\n }\n }\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n this.configure({\n chainId: providerConfig.chainId,\n });\n });\n this.getOpenSeaApiKey = getOpenSeaApiKey;\n this.addNft = addNft;\n }\n\n /**\n * Start polling for the currency rate.\n */\n async start() {\n if (!this.isMainnet() || this.disabled) {\n return;\n }\n\n await this.startPolling();\n }\n\n /**\n * Stop polling for the currency rate.\n */\n stop() {\n this.stopPolling();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n *\n * @param interval - An interval on which to poll.\n */\n private async startPolling(interval?: number): Promise<void> {\n interval && this.configure({ interval }, false, false);\n this.stopPolling();\n await this.detectNfts();\n this.intervalId = setInterval(async () => {\n await this.detectNfts();\n }, this.config.interval);\n }\n\n /**\n * Checks whether network is mainnet or not.\n *\n * @returns Whether current network is mainnet.\n */\n isMainnet = (): boolean => this.config.chainId === ChainId.mainnet;\n\n /**\n * Triggers asset ERC721 token auto detection on mainnet. Any newly detected NFTs are\n * added.\n */\n async detectNfts() {\n /* istanbul ignore if */\n if (!this.isMainnet() || this.disabled) {\n return;\n }\n const { selectedAddress, chainId } = this.config;\n\n /* istanbul ignore else */\n if (!selectedAddress) {\n return;\n }\n\n const apiNfts = await this.getOwnerNfts(selectedAddress);\n const addNftPromises = apiNfts.map(async (nft: ApiNft) => {\n const {\n token_id,\n num_sales,\n background_color,\n image_url,\n image_preview_url,\n image_thumbnail_url,\n image_original_url,\n animation_url,\n animation_original_url,\n name,\n description,\n external_link,\n creator,\n asset_contract: { address, schema_name },\n last_sale,\n } = nft;\n\n let ignored;\n /* istanbul ignore else */\n const { ignoredNfts } = this.getNftState();\n if (ignoredNfts.length) {\n ignored = ignoredNfts.find((c) => {\n /* istanbul ignore next */\n return (\n c.address === toChecksumHexAddress(address) &&\n c.tokenId === token_id\n );\n });\n }\n\n /* istanbul ignore else */\n if (!ignored) {\n /* istanbul ignore next */\n const nftMetadata: NftMetadata = Object.assign(\n {},\n { name },\n creator && { creator },\n description && { description },\n image_url && { image: image_url },\n num_sales && { numberOfSales: num_sales },\n background_color && { backgroundColor: background_color },\n image_preview_url && { imagePreview: image_preview_url },\n image_thumbnail_url && { imageThumbnail: image_thumbnail_url },\n image_original_url && { imageOriginal: image_original_url },\n animation_url && { animation: animation_url },\n animation_original_url && {\n animationOriginal: animation_original_url,\n },\n schema_name && { standard: schema_name },\n external_link && { externalLink: external_link },\n last_sale && { lastSale: last_sale },\n );\n\n await this.addNft(\n address,\n token_id,\n nftMetadata,\n {\n userAddress: selectedAddress,\n chainId,\n },\n Source.Detected,\n );\n }\n });\n await Promise.all(addNftPromises);\n }\n}\n\nexport default NftDetectionController;\n"]}
|
|
@@ -3,7 +3,7 @@ import { Contract } from '@ethersproject/contracts';
|
|
|
3
3
|
import type { AddApprovalRequest } from '@metamask/approval-controller';
|
|
4
4
|
import type { BaseConfig, BaseState, RestrictedControllerMessenger } from '@metamask/base-controller';
|
|
5
5
|
import { BaseController } from '@metamask/base-controller';
|
|
6
|
-
import type { NetworkState } from '@metamask/network-controller';
|
|
6
|
+
import type { NetworkClientId, NetworkController, NetworkState } from '@metamask/network-controller';
|
|
7
7
|
import type { PreferencesState } from '@metamask/preferences-controller';
|
|
8
8
|
import type { Hex } from '@metamask/utils';
|
|
9
9
|
import { EventEmitter } from 'events';
|
|
@@ -86,7 +86,6 @@ export declare type TokensControllerMessenger = RestrictedControllerMessenger<ty
|
|
|
86
86
|
*/
|
|
87
87
|
export declare class TokensController extends BaseController<TokensConfig, TokensState> {
|
|
88
88
|
private readonly mutex;
|
|
89
|
-
private ethersProvider;
|
|
90
89
|
private abortController;
|
|
91
90
|
private readonly messagingSystem;
|
|
92
91
|
/**
|
|
@@ -105,6 +104,7 @@ export declare class TokensController extends BaseController<TokensConfig, Token
|
|
|
105
104
|
*/
|
|
106
105
|
name: string;
|
|
107
106
|
private readonly getERC20TokenName;
|
|
107
|
+
private readonly getNetworkClientById;
|
|
108
108
|
/**
|
|
109
109
|
* Creates a TokensController instance.
|
|
110
110
|
*
|
|
@@ -114,44 +114,51 @@ export declare class TokensController extends BaseController<TokensConfig, Token
|
|
|
114
114
|
* @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
|
|
115
115
|
* @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.
|
|
116
116
|
* @param options.getERC20TokenName - Gets the ERC-20 token name.
|
|
117
|
+
* @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.
|
|
117
118
|
* @param options.config - Initial options used to configure this controller.
|
|
118
119
|
* @param options.state - Initial state to set on this controller.
|
|
119
120
|
* @param options.messenger - The controller messenger.
|
|
120
121
|
*/
|
|
121
|
-
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, onTokenListStateChange, getERC20TokenName, config, state, messenger, }: {
|
|
122
|
+
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, onTokenListStateChange, getERC20TokenName, getNetworkClientById, config, state, messenger, }: {
|
|
122
123
|
chainId: Hex;
|
|
123
124
|
onPreferencesStateChange: (listener: (preferencesState: PreferencesState) => void) => void;
|
|
124
125
|
onNetworkStateChange: (listener: (networkState: NetworkState) => void) => void;
|
|
125
126
|
onTokenListStateChange: (listener: (tokenListState: TokenListState) => void) => void;
|
|
126
127
|
getERC20TokenName: AssetsContractController['getERC20TokenName'];
|
|
128
|
+
getNetworkClientById: NetworkController['getNetworkClientById'];
|
|
127
129
|
config?: Partial<TokensConfig>;
|
|
128
130
|
state?: Partial<TokensState>;
|
|
129
131
|
messenger: TokensControllerMessenger;
|
|
130
132
|
});
|
|
131
|
-
_instantiateNewEthersProvider(): any;
|
|
132
133
|
/**
|
|
133
134
|
* Adds a token to the stored token list.
|
|
134
135
|
*
|
|
135
|
-
* @param
|
|
136
|
-
* @param
|
|
137
|
-
* @param
|
|
138
|
-
* @param options -
|
|
139
|
-
* @param options.name - Name of the token
|
|
140
|
-
* @param options.image - Image of the token
|
|
136
|
+
* @param options - The method argument object.
|
|
137
|
+
* @param options.address - Hex address of the token contract.
|
|
138
|
+
* @param options.symbol - Symbol of the token.
|
|
139
|
+
* @param options.decimals - Number of decimals the token uses.
|
|
140
|
+
* @param options.name - Name of the token.
|
|
141
|
+
* @param options.image - Image of the token.
|
|
141
142
|
* @param options.interactingAddress - The address of the account to add a token to.
|
|
143
|
+
* @param options.networkClientId - Network Client ID.
|
|
142
144
|
* @returns Current token list.
|
|
143
145
|
*/
|
|
144
|
-
addToken(address
|
|
146
|
+
addToken({ address, symbol, decimals, name, image, interactingAddress, networkClientId, }: {
|
|
147
|
+
address: string;
|
|
148
|
+
symbol: string;
|
|
149
|
+
decimals: number;
|
|
145
150
|
name?: string;
|
|
146
151
|
image?: string;
|
|
147
152
|
interactingAddress?: string;
|
|
153
|
+
networkClientId?: NetworkClientId;
|
|
148
154
|
}): Promise<Token[]>;
|
|
149
155
|
/**
|
|
150
156
|
* Add a batch of tokens.
|
|
151
157
|
*
|
|
152
158
|
* @param tokensToImport - Array of tokens to import.
|
|
159
|
+
* @param networkClientId - Optional network client ID used to determine interacting chain ID.
|
|
153
160
|
*/
|
|
154
|
-
addTokens(tokensToImport: Token[]): Promise<void>;
|
|
161
|
+
addTokens(tokensToImport: Token[], networkClientId?: NetworkClientId): Promise<void>;
|
|
155
162
|
/**
|
|
156
163
|
* Ignore a batch of tokens.
|
|
157
164
|
*
|
|
@@ -189,22 +196,30 @@ export declare class TokensController extends BaseController<TokensConfig, Token
|
|
|
189
196
|
* Detects whether or not a token is ERC-721 compatible.
|
|
190
197
|
*
|
|
191
198
|
* @param tokenAddress - The token contract address.
|
|
199
|
+
* @param networkClientId - Optional network client ID to fetch contract info with.
|
|
192
200
|
* @returns A boolean indicating whether the token address passed in supports the EIP-721
|
|
193
201
|
* interface.
|
|
194
202
|
*/
|
|
195
|
-
_detectIsERC721(tokenAddress: string): Promise<any>;
|
|
196
|
-
_createEthersContract(tokenAddress: string, abi: string,
|
|
203
|
+
_detectIsERC721(tokenAddress: string, networkClientId?: NetworkClientId): Promise<any>;
|
|
204
|
+
_createEthersContract(tokenAddress: string, abi: string, networkClientId?: NetworkClientId): Contract;
|
|
197
205
|
_generateRandomId(): string;
|
|
198
206
|
/**
|
|
199
207
|
* Adds a new suggestedAsset to the list of watched assets.
|
|
200
208
|
* Parameters will be validated according to the asset type being watched.
|
|
201
209
|
*
|
|
202
|
-
* @param
|
|
203
|
-
* @param
|
|
204
|
-
* @param
|
|
210
|
+
* @param options - The method options.
|
|
211
|
+
* @param options.asset - The asset to be watched. For now only ERC20 tokens are accepted.
|
|
212
|
+
* @param options.type - The asset type.
|
|
213
|
+
* @param options.interactingAddress - The address of the account that is requesting to watch the asset.
|
|
214
|
+
* @param options.networkClientId - Network Client ID.
|
|
205
215
|
* @returns Object containing a Promise resolving to the suggestedAsset address if accepted.
|
|
206
216
|
*/
|
|
207
|
-
watchAsset(asset
|
|
217
|
+
watchAsset({ asset, type, interactingAddress, networkClientId, }: {
|
|
218
|
+
asset: Token;
|
|
219
|
+
type: string;
|
|
220
|
+
interactingAddress?: string;
|
|
221
|
+
networkClientId?: NetworkClientId;
|
|
222
|
+
}): Promise<void>;
|
|
208
223
|
/**
|
|
209
224
|
* Takes a new tokens and ignoredTokens array for the current network/account combination
|
|
210
225
|
* and returns new allTokens and allIgnoredTokens state to update to.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,EACV,UAAU,EACV,SAAS,EACT,6BAA6B,EAC9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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"}
|
package/dist/TokensController.js
CHANGED
|
@@ -42,11 +42,12 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
42
42
|
* @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
|
|
43
43
|
* @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.
|
|
44
44
|
* @param options.getERC20TokenName - Gets the ERC-20 token name.
|
|
45
|
+
* @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.
|
|
45
46
|
* @param options.config - Initial options used to configure this controller.
|
|
46
47
|
* @param options.state - Initial state to set on this controller.
|
|
47
48
|
* @param options.messenger - The controller messenger.
|
|
48
49
|
*/
|
|
49
|
-
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, onTokenListStateChange, getERC20TokenName, config, state, messenger, }) {
|
|
50
|
+
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, onTokenListStateChange, getERC20TokenName, getNetworkClientById, config, state, messenger, }) {
|
|
50
51
|
super(config, state);
|
|
51
52
|
this.mutex = new async_mutex_1.Mutex();
|
|
52
53
|
/**
|
|
@@ -62,6 +63,7 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
62
63
|
this.initialize();
|
|
63
64
|
this.abortController = new abort_controller_1.AbortController();
|
|
64
65
|
this.getERC20TokenName = getERC20TokenName;
|
|
66
|
+
this.getNetworkClientById = getNetworkClientById;
|
|
65
67
|
this.messagingSystem = messenger;
|
|
66
68
|
onPreferencesStateChange(({ selectedAddress }) => {
|
|
67
69
|
var _a, _b, _c;
|
|
@@ -82,7 +84,6 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
82
84
|
this.abortController.abort();
|
|
83
85
|
this.abortController = new abort_controller_1.AbortController();
|
|
84
86
|
this.configure({ chainId });
|
|
85
|
-
this.ethersProvider = this._instantiateNewEthersProvider();
|
|
86
87
|
this.update({
|
|
87
88
|
tokens: ((_a = allTokens[chainId]) === null || _a === void 0 ? void 0 : _a[selectedAddress]) || [],
|
|
88
89
|
ignoredTokens: ((_b = allIgnoredTokens[chainId]) === null || _b === void 0 ? void 0 : _b[selectedAddress]) || [],
|
|
@@ -117,27 +118,29 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
117
118
|
}
|
|
118
119
|
});
|
|
119
120
|
}
|
|
120
|
-
_instantiateNewEthersProvider() {
|
|
121
|
-
var _a;
|
|
122
|
-
return new providers_1.Web3Provider((_a = this.config) === null || _a === void 0 ? void 0 : _a.provider);
|
|
123
|
-
}
|
|
124
121
|
/**
|
|
125
122
|
* Adds a token to the stored token list.
|
|
126
123
|
*
|
|
127
|
-
* @param
|
|
128
|
-
* @param
|
|
129
|
-
* @param
|
|
130
|
-
* @param options -
|
|
131
|
-
* @param options.name - Name of the token
|
|
132
|
-
* @param options.image - Image of the token
|
|
124
|
+
* @param options - The method argument object.
|
|
125
|
+
* @param options.address - Hex address of the token contract.
|
|
126
|
+
* @param options.symbol - Symbol of the token.
|
|
127
|
+
* @param options.decimals - Number of decimals the token uses.
|
|
128
|
+
* @param options.name - Name of the token.
|
|
129
|
+
* @param options.image - Image of the token.
|
|
133
130
|
* @param options.interactingAddress - The address of the account to add a token to.
|
|
131
|
+
* @param options.networkClientId - Network Client ID.
|
|
134
132
|
* @returns Current token list.
|
|
135
133
|
*/
|
|
136
|
-
addToken(address, symbol, decimals,
|
|
134
|
+
addToken({ address, symbol, decimals, name, image, interactingAddress, networkClientId, }) {
|
|
137
135
|
var _a, _b, _c;
|
|
138
136
|
return __awaiter(this, void 0, void 0, function* () {
|
|
139
137
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
140
|
-
const { chainId
|
|
138
|
+
const { chainId, selectedAddress } = this.config;
|
|
139
|
+
let currentChainId = chainId;
|
|
140
|
+
if (networkClientId) {
|
|
141
|
+
currentChainId =
|
|
142
|
+
this.getNetworkClientById(networkClientId).configuration.chainId;
|
|
143
|
+
}
|
|
141
144
|
const accountAddress = interactingAddress || selectedAddress;
|
|
142
145
|
const isInteractingWithWalletAccount = accountAddress === selectedAddress;
|
|
143
146
|
const releaseLock = yield this.mutex.acquire();
|
|
@@ -148,10 +151,10 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
148
151
|
const detectedTokens = ((_c = allDetectedTokens[currentChainId]) === null || _c === void 0 ? void 0 : _c[accountAddress]) || [];
|
|
149
152
|
const newTokens = [...tokens];
|
|
150
153
|
const [isERC721, tokenMetadata] = yield Promise.all([
|
|
151
|
-
this._detectIsERC721(address),
|
|
154
|
+
this._detectIsERC721(address, networkClientId),
|
|
152
155
|
this.fetchTokenMetadata(address),
|
|
153
156
|
]);
|
|
154
|
-
if (currentChainId !== this.config.chainId) {
|
|
157
|
+
if (!networkClientId && currentChainId !== this.config.chainId) {
|
|
155
158
|
throw new Error('TokensController Error: Switched networks while adding token');
|
|
156
159
|
}
|
|
157
160
|
const newEntry = {
|
|
@@ -160,7 +163,7 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
160
163
|
decimals,
|
|
161
164
|
image: image ||
|
|
162
165
|
(0, assetsUtil_1.formatIconUrlWithProxy)({
|
|
163
|
-
chainId:
|
|
166
|
+
chainId: currentChainId,
|
|
164
167
|
tokenAddress: address,
|
|
165
168
|
}),
|
|
166
169
|
isERC721,
|
|
@@ -182,6 +185,7 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
182
185
|
newIgnoredTokens,
|
|
183
186
|
newDetectedTokens,
|
|
184
187
|
interactingAddress: accountAddress,
|
|
188
|
+
interactingChainId: currentChainId,
|
|
185
189
|
});
|
|
186
190
|
let newState = {
|
|
187
191
|
allTokens: newAllTokens,
|
|
@@ -204,8 +208,9 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
204
208
|
* Add a batch of tokens.
|
|
205
209
|
*
|
|
206
210
|
* @param tokensToImport - Array of tokens to import.
|
|
211
|
+
* @param networkClientId - Optional network client ID used to determine interacting chain ID.
|
|
207
212
|
*/
|
|
208
|
-
addTokens(tokensToImport) {
|
|
213
|
+
addTokens(tokensToImport, networkClientId) {
|
|
209
214
|
return __awaiter(this, void 0, void 0, function* () {
|
|
210
215
|
const releaseLock = yield this.mutex.acquire();
|
|
211
216
|
const { tokens, detectedTokens, ignoredTokens } = this.state;
|
|
@@ -234,10 +239,16 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
234
239
|
const newTokens = Object.values(newTokensMap);
|
|
235
240
|
const newDetectedTokens = detectedTokens.filter((token) => !importedTokensMap[token.address.toLowerCase()]);
|
|
236
241
|
const newIgnoredTokens = ignoredTokens.filter((tokenAddress) => !newTokensMap[tokenAddress.toLowerCase()]);
|
|
242
|
+
let interactingChainId;
|
|
243
|
+
if (networkClientId) {
|
|
244
|
+
interactingChainId =
|
|
245
|
+
this.getNetworkClientById(networkClientId).configuration.chainId;
|
|
246
|
+
}
|
|
237
247
|
const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } = this._getNewAllTokensState({
|
|
238
248
|
newTokens,
|
|
239
249
|
newDetectedTokens,
|
|
240
250
|
newIgnoredTokens,
|
|
251
|
+
interactingChainId,
|
|
241
252
|
});
|
|
242
253
|
this.update({
|
|
243
254
|
tokens: newTokens,
|
|
@@ -396,10 +407,11 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
396
407
|
* Detects whether or not a token is ERC-721 compatible.
|
|
397
408
|
*
|
|
398
409
|
* @param tokenAddress - The token contract address.
|
|
410
|
+
* @param networkClientId - Optional network client ID to fetch contract info with.
|
|
399
411
|
* @returns A boolean indicating whether the token address passed in supports the EIP-721
|
|
400
412
|
* interface.
|
|
401
413
|
*/
|
|
402
|
-
_detectIsERC721(tokenAddress) {
|
|
414
|
+
_detectIsERC721(tokenAddress, networkClientId) {
|
|
403
415
|
var _a, _b;
|
|
404
416
|
return __awaiter(this, void 0, void 0, function* () {
|
|
405
417
|
const checksumAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress);
|
|
@@ -411,7 +423,7 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
411
423
|
else if (((_b = contract_metadata_1.default[checksumAddress]) === null || _b === void 0 ? void 0 : _b.erc20) === true) {
|
|
412
424
|
return Promise.resolve(false);
|
|
413
425
|
}
|
|
414
|
-
const tokenContract = this._createEthersContract(tokenAddress, metamask_eth_abis_1.abiERC721,
|
|
426
|
+
const tokenContract = this._createEthersContract(tokenAddress, metamask_eth_abis_1.abiERC721, networkClientId);
|
|
415
427
|
try {
|
|
416
428
|
return yield tokenContract.supportsInterface(controller_utils_1.ERC721_INTERFACE_ID);
|
|
417
429
|
}
|
|
@@ -424,8 +436,13 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
424
436
|
}
|
|
425
437
|
});
|
|
426
438
|
}
|
|
427
|
-
_createEthersContract(tokenAddress, abi,
|
|
428
|
-
|
|
439
|
+
_createEthersContract(tokenAddress, abi, networkClientId) {
|
|
440
|
+
var _a;
|
|
441
|
+
const provider = networkClientId
|
|
442
|
+
? this.getNetworkClientById(networkClientId).provider
|
|
443
|
+
: (_a = this.config) === null || _a === void 0 ? void 0 : _a.provider;
|
|
444
|
+
const web3provider = new providers_1.Web3Provider(provider);
|
|
445
|
+
const tokenContract = new contracts_1.Contract(tokenAddress, abi, web3provider);
|
|
429
446
|
return tokenContract;
|
|
430
447
|
}
|
|
431
448
|
_generateRandomId() {
|
|
@@ -435,12 +452,14 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
435
452
|
* Adds a new suggestedAsset to the list of watched assets.
|
|
436
453
|
* Parameters will be validated according to the asset type being watched.
|
|
437
454
|
*
|
|
438
|
-
* @param
|
|
439
|
-
* @param
|
|
440
|
-
* @param
|
|
455
|
+
* @param options - The method options.
|
|
456
|
+
* @param options.asset - The asset to be watched. For now only ERC20 tokens are accepted.
|
|
457
|
+
* @param options.type - The asset type.
|
|
458
|
+
* @param options.interactingAddress - The address of the account that is requesting to watch the asset.
|
|
459
|
+
* @param options.networkClientId - Network Client ID.
|
|
441
460
|
* @returns Object containing a Promise resolving to the suggestedAsset address if accepted.
|
|
442
461
|
*/
|
|
443
|
-
watchAsset(asset, type, interactingAddress) {
|
|
462
|
+
watchAsset({ asset, type, interactingAddress, networkClientId, }) {
|
|
444
463
|
return __awaiter(this, void 0, void 0, function* () {
|
|
445
464
|
if (type !== controller_utils_1.ERC20) {
|
|
446
465
|
throw new Error(`Asset of type ${type} not supported`);
|
|
@@ -457,15 +476,20 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
457
476
|
yield this._requestApproval(suggestedAssetMeta);
|
|
458
477
|
let name;
|
|
459
478
|
try {
|
|
460
|
-
name = yield this.getERC20TokenName(asset.address);
|
|
479
|
+
name = yield this.getERC20TokenName(asset.address, networkClientId);
|
|
461
480
|
}
|
|
462
481
|
catch (error) {
|
|
463
482
|
name = undefined;
|
|
464
483
|
}
|
|
465
|
-
|
|
484
|
+
const { address, symbol, decimals, image } = asset;
|
|
485
|
+
yield this.addToken({
|
|
486
|
+
address,
|
|
487
|
+
symbol,
|
|
488
|
+
decimals,
|
|
466
489
|
name,
|
|
467
|
-
image
|
|
490
|
+
image,
|
|
468
491
|
interactingAddress: suggestedAssetMeta.interactingAddress,
|
|
492
|
+
networkClientId,
|
|
469
493
|
});
|
|
470
494
|
});
|
|
471
495
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokensController.js","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { AddApprovalRequest } from '@metamask/approval-controller';\nimport type {\n BaseConfig,\n BaseState,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport contractsMap from '@metamask/contract-metadata';\nimport {\n toChecksumHexAddress,\n ERC721_INTERFACE_ID,\n ORIGIN_METAMASK,\n ApprovalType,\n ERC20,\n} from '@metamask/controller-utils';\nimport { abiERC721 } from '@metamask/metamask-eth-abis';\nimport type { NetworkState } from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { AbortController as WhatwgAbortController } from 'abort-controller';\nimport { Mutex } from 'async-mutex';\nimport { EventEmitter } from 'events';\nimport { v1 as random } from 'uuid';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport {\n formatAggregatorNames,\n formatIconUrlWithProxy,\n validateTokenToWatch,\n} from './assetsUtil';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from './token-service';\nimport type {\n TokenListMap,\n TokenListState,\n TokenListToken,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\n\n/**\n * @type TokensConfig\n *\n * Tokens controller configuration\n * @property selectedAddress - Vault selected address\n */\nexport interface TokensConfig extends BaseConfig {\n selectedAddress: string;\n chainId: Hex;\n provider: any;\n}\n\n/**\n * @type SuggestedAssetMeta\n *\n * Suggested asset by EIP747 meta data\n * @property id - Generated UUID associated with this suggested asset\n * @property time - Timestamp associated with this this suggested asset\n * @property type - Type type this suggested asset\n * @property asset - Asset suggested object\n * @property interactingAddress - Account address that requested watch asset\n */\ntype SuggestedAssetMeta = {\n id: string;\n time: number;\n type: string;\n asset: Token;\n interactingAddress: string;\n};\n\n/**\n * @type TokensState\n *\n * Assets controller state\n * @property tokens - List of tokens associated with the active network and address pair\n * @property ignoredTokens - List of ignoredTokens associated with the active network and address pair\n * @property detectedTokens - List of detected tokens associated with the active network and address pair\n * @property allTokens - Object containing tokens by network and account\n * @property allIgnoredTokens - Object containing hidden/ignored tokens by network and account\n * @property allDetectedTokens - Object containing tokens detected with non-zero balances\n */\nexport interface TokensState extends BaseState {\n tokens: Token[];\n ignoredTokens: string[];\n detectedTokens: Token[];\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allIgnoredTokens: { [chainId: Hex]: { [key: string]: string[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n}\n\n/**\n * The name of the {@link TokensController}.\n */\nconst controllerName = 'TokensController';\n\n/**\n * The external actions available to the {@link TokensController}.\n */\ntype AllowedActions = AddApprovalRequest;\n\n/**\n * The messenger of the {@link TokensController}.\n */\nexport type TokensControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n AllowedActions,\n never,\n AllowedActions['type'],\n never\n>;\n\n/**\n * Controller that stores assets and exposes convenience methods\n */\nexport class TokensController extends BaseController<\n TokensConfig,\n TokensState\n> {\n private readonly mutex = new Mutex();\n\n private ethersProvider: any;\n\n private abortController: WhatwgAbortController;\n\n private readonly messagingSystem: TokensControllerMessenger;\n\n /**\n * Fetch metadata for a token.\n *\n * @param tokenAddress - The address of the token.\n * @returns The token metadata.\n */\n private async fetchTokenMetadata(\n tokenAddress: string,\n ): Promise<TokenListToken | undefined> {\n try {\n const token = await fetchTokenMetadata<TokenListToken>(\n this.config.chainId,\n tokenAddress,\n this.abortController.signal,\n );\n return token;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * EventEmitter instance used to listen to specific EIP747 events\n */\n hub = new EventEmitter();\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokensController';\n\n private readonly getERC20TokenName: AssetsContractController['getERC20TokenName'];\n\n /**\n * Creates a TokensController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.\n * @param options.getERC20TokenName - Gets the ERC-20 token name.\n * @param options.config - Initial options used to configure this controller.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messenger.\n */\n constructor({\n chainId: initialChainId,\n onPreferencesStateChange,\n onNetworkStateChange,\n onTokenListStateChange,\n getERC20TokenName,\n config,\n state,\n messenger,\n }: {\n chainId: Hex;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n onTokenListStateChange: (\n listener: (tokenListState: TokenListState) => void,\n ) => void;\n getERC20TokenName: AssetsContractController['getERC20TokenName'];\n config?: Partial<TokensConfig>;\n state?: Partial<TokensState>;\n messenger: TokensControllerMessenger;\n }) {\n super(config, state);\n\n this.defaultConfig = {\n selectedAddress: '',\n chainId: initialChainId,\n provider: undefined,\n ...config,\n };\n\n this.defaultState = {\n tokens: [],\n ignoredTokens: [],\n detectedTokens: [],\n allTokens: {},\n allIgnoredTokens: {},\n allDetectedTokens: {},\n ...state,\n };\n\n this.initialize();\n this.abortController = new WhatwgAbortController();\n this.getERC20TokenName = getERC20TokenName;\n\n this.messagingSystem = messenger;\n\n onPreferencesStateChange(({ selectedAddress }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = this.config;\n this.configure({ selectedAddress });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { selectedAddress } = this.config;\n const { chainId } = providerConfig;\n this.abortController.abort();\n this.abortController = new WhatwgAbortController();\n this.configure({ chainId });\n this.ethersProvider = this._instantiateNewEthersProvider();\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onTokenListStateChange(({ tokenList }) => {\n const { tokens } = this.state;\n if (tokens.length && !tokens[0].name) {\n this.updateTokensAttribute(tokenList, 'name');\n }\n });\n }\n\n _instantiateNewEthersProvider(): any {\n return new Web3Provider(this.config?.provider);\n }\n\n /**\n * Adds a token to the stored token list.\n *\n * @param address - Hex address of the token contract.\n * @param symbol - Symbol of the token.\n * @param decimals - Number of decimals the token uses.\n * @param options - Object containing name and image of the token\n * @param options.name - Name of the token\n * @param options.image - Image of the token\n * @param options.interactingAddress - The address of the account to add a token to.\n * @returns Current token list.\n */\n async addToken(\n address: string,\n symbol: string,\n decimals: number,\n {\n name,\n image,\n interactingAddress,\n }: { name?: string; image?: string; interactingAddress?: string } = {},\n ): Promise<Token[]> {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId: currentChainId, selectedAddress } = this.config;\n const accountAddress = interactingAddress || selectedAddress;\n const isInteractingWithWalletAccount = accountAddress === selectedAddress;\n const releaseLock = await this.mutex.acquire();\n\n try {\n address = toChecksumHexAddress(address);\n const tokens = allTokens[currentChainId]?.[accountAddress] || [];\n const ignoredTokens =\n allIgnoredTokens[currentChainId]?.[accountAddress] || [];\n const detectedTokens =\n allDetectedTokens[currentChainId]?.[accountAddress] || [];\n const newTokens: Token[] = [...tokens];\n const [isERC721, tokenMetadata] = await Promise.all([\n this._detectIsERC721(address),\n this.fetchTokenMetadata(address),\n ]);\n if (currentChainId !== this.config.chainId) {\n throw new Error(\n 'TokensController Error: Switched networks while adding token',\n );\n }\n const newEntry: Token = {\n address,\n symbol,\n decimals,\n image:\n image ||\n formatIconUrlWithProxy({\n chainId: this.config.chainId,\n tokenAddress: address,\n }),\n isERC721,\n aggregators: formatAggregatorNames(tokenMetadata?.aggregators || []),\n name,\n };\n const previousEntry = newTokens.find(\n (token) => token.address.toLowerCase() === address.toLowerCase(),\n );\n if (previousEntry) {\n const previousIndex = newTokens.indexOf(previousEntry);\n newTokens[previousIndex] = newEntry;\n } else {\n newTokens.push(newEntry);\n }\n\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => tokenAddress.toLowerCase() !== address.toLowerCase(),\n );\n const newDetectedTokens = detectedTokens.filter(\n (token) => token.address.toLowerCase() !== address.toLowerCase(),\n );\n\n const { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens } =\n this._getNewAllTokensState({\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n interactingAddress: accountAddress,\n });\n\n let newState: Partial<TokensState> = {\n allTokens: newAllTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n };\n\n // Only update active tokens if user is interacting with their active wallet account.\n if (isInteractingWithWalletAccount) {\n newState = {\n ...newState,\n tokens: newTokens,\n ignoredTokens: newIgnoredTokens,\n detectedTokens: newDetectedTokens,\n };\n }\n\n this.update(newState);\n return newTokens;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Add a batch of tokens.\n *\n * @param tokensToImport - Array of tokens to import.\n */\n async addTokens(tokensToImport: Token[]) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const importedTokensMap: { [key: string]: true } = {};\n // Used later to dedupe imported tokens\n const newTokensMap = tokens.reduce((output, current) => {\n output[current.address] = current;\n return output;\n }, {} as { [address: string]: Token });\n try {\n tokensToImport.forEach((tokenToAdd) => {\n const { address, symbol, decimals, image, aggregators, name } =\n tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const formattedToken: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n aggregators,\n name,\n };\n newTokensMap[address] = formattedToken;\n importedTokensMap[address.toLowerCase()] = true;\n return formattedToken;\n });\n const newTokens = Object.values(newTokensMap);\n\n const newDetectedTokens = detectedTokens.filter(\n (token) => !importedTokensMap[token.address.toLowerCase()],\n );\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => !newTokensMap[tokenAddress.toLowerCase()],\n );\n\n const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } =\n this._getNewAllTokensState({\n newTokens,\n newDetectedTokens,\n newIgnoredTokens,\n });\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n ignoredTokens: newIgnoredTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Ignore a batch of tokens.\n *\n * @param tokenAddressesToIgnore - Array of token addresses to ignore.\n */\n ignoreTokens(tokenAddressesToIgnore: string[]) {\n const { ignoredTokens, detectedTokens, tokens } = this.state;\n const ignoredTokensMap: { [key: string]: true } = {};\n let newIgnoredTokens: string[] = [...ignoredTokens];\n\n const checksummedTokenAddresses = tokenAddressesToIgnore.map((address) => {\n const checksumAddress = toChecksumHexAddress(address);\n ignoredTokensMap[address.toLowerCase()] = true;\n return checksumAddress;\n });\n newIgnoredTokens = [...ignoredTokens, ...checksummedTokenAddresses];\n const newDetectedTokens = detectedTokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n const newTokens = tokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n\n const { newAllIgnoredTokens, newAllDetectedTokens, newAllTokens } =\n this._getNewAllTokensState({\n newIgnoredTokens,\n newDetectedTokens,\n newTokens,\n });\n\n this.update({\n ignoredTokens: newIgnoredTokens,\n tokens: newTokens,\n detectedTokens: newDetectedTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n allTokens: newAllTokens,\n });\n }\n\n /**\n * Adds a batch of detected tokens to the stored token list.\n *\n * @param incomingDetectedTokens - Array of detected tokens to be added or updated.\n * @param detectionDetails - An object containing the chain ID and address of the currently selected network on which the incomingDetectedTokens were detected.\n * @param detectionDetails.selectedAddress - the account address on which the incomingDetectedTokens were detected.\n * @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.\n */\n async addDetectedTokens(\n incomingDetectedTokens: Token[],\n detectionDetails?: { selectedAddress: string; chainId: Hex },\n ) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const newTokens: Token[] = [...tokens];\n let newDetectedTokens: Token[] = [...detectedTokens];\n\n try {\n incomingDetectedTokens.forEach((tokenToAdd) => {\n const {\n address,\n symbol,\n decimals,\n image,\n aggregators,\n isERC721,\n name,\n } = tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const newEntry: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n isERC721,\n aggregators,\n name,\n };\n const previousImportedEntry = newTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousImportedEntry) {\n // Update existing data of imported token\n const previousImportedIndex = newTokens.indexOf(\n previousImportedEntry,\n );\n newTokens[previousImportedIndex] = newEntry;\n } else {\n const ignoredTokenIndex = ignoredTokens.indexOf(address);\n if (ignoredTokenIndex === -1) {\n // Add detected token\n const previousDetectedEntry = newDetectedTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousDetectedEntry) {\n const previousDetectedIndex = newDetectedTokens.indexOf(\n previousDetectedEntry,\n );\n newDetectedTokens[previousDetectedIndex] = newEntry;\n } else {\n newDetectedTokens.push(newEntry);\n }\n }\n }\n });\n\n const {\n selectedAddress: interactingAddress,\n chainId: interactingChainId,\n } = detectionDetails || {};\n\n const { newAllTokens, newAllDetectedTokens } = this._getNewAllTokensState(\n {\n newTokens,\n newDetectedTokens,\n interactingAddress,\n interactingChainId,\n },\n );\n\n const { chainId, selectedAddress } = this.config;\n // if the newly added detectedTokens were detected on (and therefore added to) a different chainId/selectedAddress than the currently configured combo\n // the newDetectedTokens (which should contain the detectedTokens on the current chainId/address combo) needs to be repointed to the current chainId/address pair\n // if the detectedTokens were detected on the current chainId/address then this won't change anything.\n newDetectedTokens =\n newAllDetectedTokens?.[chainId]?.[selectedAddress] || [];\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Adds isERC721 field to token object. This is called when a user attempts to add tokens that\n * were previously added which do not yet had isERC721 field.\n *\n * @param tokenAddress - The contract address of the token requiring the isERC721 field added.\n * @returns The new token object with the added isERC721 field.\n */\n async updateTokenType(tokenAddress: string) {\n const isERC721 = await this._detectIsERC721(tokenAddress);\n const { tokens } = this.state;\n const tokenIndex = tokens.findIndex((token) => {\n return token.address.toLowerCase() === tokenAddress.toLowerCase();\n });\n tokens[tokenIndex].isERC721 = isERC721;\n this.update({ tokens });\n return tokens[tokenIndex];\n }\n\n /**\n * This is a function that updates the tokens name for the tokens name if it is not defined.\n *\n * @param tokenList - Represents the fetched token list from service API\n * @param tokenAttribute - Represents the token attribute that we want to update on the token list\n */\n private updateTokensAttribute(\n tokenList: TokenListMap,\n tokenAttribute: keyof Token & keyof TokenListToken,\n ) {\n const { tokens } = this.state;\n\n const newTokens = tokens.map((token) => {\n const newToken = tokenList[token.address.toLowerCase()];\n\n return !token[tokenAttribute] && newToken?.[tokenAttribute]\n ? { ...token, [tokenAttribute]: newToken[tokenAttribute] }\n : { ...token };\n });\n\n this.update({ tokens: newTokens });\n }\n\n /**\n * Detects whether or not a token is ERC-721 compatible.\n *\n * @param tokenAddress - The token contract address.\n * @returns A boolean indicating whether the token address passed in supports the EIP-721\n * interface.\n */\n async _detectIsERC721(tokenAddress: string) {\n const checksumAddress = toChecksumHexAddress(tokenAddress);\n // if this token is already in our contract metadata map we don't need\n // to check against the contract\n if (contractsMap[checksumAddress]?.erc721 === true) {\n return Promise.resolve(true);\n } else if (contractsMap[checksumAddress]?.erc20 === true) {\n return Promise.resolve(false);\n }\n\n const tokenContract = this._createEthersContract(\n tokenAddress,\n abiERC721,\n this.ethersProvider,\n );\n try {\n return await tokenContract.supportsInterface(ERC721_INTERFACE_ID);\n } catch (error: any) {\n // currently we see a variety of errors across different networks when\n // token contracts are not ERC721 compatible. We need to figure out a better\n // way of differentiating token interface types but for now if we get an error\n // we have to assume the token is not ERC721 compatible.\n return false;\n }\n }\n\n _createEthersContract(\n tokenAddress: string,\n abi: string,\n ethersProvider: any,\n ): Contract {\n const tokenContract = new Contract(tokenAddress, abi, ethersProvider);\n return tokenContract;\n }\n\n _generateRandomId(): string {\n return random();\n }\n\n /**\n * Adds a new suggestedAsset to the list of watched assets.\n * Parameters will be validated according to the asset type being watched.\n *\n * @param asset - The asset to be watched. For now only ERC20 tokens are accepted.\n * @param type - The asset type.\n * @param interactingAddress - The address of the account that is requesting to watch the asset.\n * @returns Object containing a Promise resolving to the suggestedAsset address if accepted.\n */\n async watchAsset(\n asset: Token,\n type: string,\n interactingAddress?: string,\n ): Promise<void> {\n if (type !== ERC20) {\n throw new Error(`Asset of type ${type} not supported`);\n }\n\n const { selectedAddress } = this.config;\n\n const suggestedAssetMeta: SuggestedAssetMeta = {\n asset,\n id: this._generateRandomId(),\n time: Date.now(),\n type,\n interactingAddress: interactingAddress || selectedAddress,\n };\n\n validateTokenToWatch(asset);\n\n await this._requestApproval(suggestedAssetMeta);\n\n let name;\n try {\n name = await this.getERC20TokenName(asset.address);\n } catch (error) {\n name = undefined;\n }\n\n await this.addToken(asset.address, asset.symbol, asset.decimals, {\n name,\n image: asset.image,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n });\n }\n\n /**\n * Takes a new tokens and ignoredTokens array for the current network/account combination\n * and returns new allTokens and allIgnoredTokens state to update to.\n *\n * @param params - Object that holds token params.\n * @param params.newTokens - The new tokens to set for the current network and selected account.\n * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.\n * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.\n * @param params.interactingAddress - The account address to use to store the tokens.\n * @param params.interactingChainId - The chainId to use to store the tokens.\n * @returns The updated `allTokens` and `allIgnoredTokens` state.\n */\n _getNewAllTokensState(params: {\n newTokens?: Token[];\n newIgnoredTokens?: string[];\n newDetectedTokens?: Token[];\n interactingAddress?: string;\n interactingChainId?: Hex;\n }) {\n const {\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n interactingAddress,\n interactingChainId,\n } = params;\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId, selectedAddress } = this.config;\n\n const userAddressToAddTokens = interactingAddress ?? selectedAddress;\n const chainIdToAddTokens = interactingChainId ?? chainId;\n\n let newAllTokens = allTokens;\n if (\n newTokens?.length ||\n (newTokens &&\n allTokens &&\n allTokens[chainIdToAddTokens] &&\n allTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkTokens = allTokens[chainIdToAddTokens];\n const newNetworkTokens = {\n ...networkTokens,\n ...{ [userAddressToAddTokens]: newTokens },\n };\n newAllTokens = {\n ...allTokens,\n ...{ [chainIdToAddTokens]: newNetworkTokens },\n };\n }\n\n let newAllIgnoredTokens = allIgnoredTokens;\n if (\n newIgnoredTokens?.length ||\n (newIgnoredTokens &&\n allIgnoredTokens &&\n allIgnoredTokens[chainIdToAddTokens] &&\n allIgnoredTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkIgnoredTokens = allIgnoredTokens[chainIdToAddTokens];\n const newIgnoredNetworkTokens = {\n ...networkIgnoredTokens,\n ...{ [userAddressToAddTokens]: newIgnoredTokens },\n };\n newAllIgnoredTokens = {\n ...allIgnoredTokens,\n ...{ [chainIdToAddTokens]: newIgnoredNetworkTokens },\n };\n }\n\n let newAllDetectedTokens = allDetectedTokens;\n if (\n newDetectedTokens?.length ||\n (newDetectedTokens &&\n allDetectedTokens &&\n allDetectedTokens[chainIdToAddTokens] &&\n allDetectedTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkDetectedTokens = allDetectedTokens[chainIdToAddTokens];\n const newDetectedNetworkTokens = {\n ...networkDetectedTokens,\n ...{ [userAddressToAddTokens]: newDetectedTokens },\n };\n newAllDetectedTokens = {\n ...allDetectedTokens,\n ...{ [chainIdToAddTokens]: newDetectedNetworkTokens },\n };\n }\n return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };\n }\n\n /**\n * Removes all tokens from the ignored list.\n */\n clearIgnoredTokens() {\n this.update({ ignoredTokens: [], allIgnoredTokens: {} });\n }\n\n async _requestApproval(suggestedAssetMeta: SuggestedAssetMeta) {\n return this.messagingSystem.call(\n 'ApprovalController:addRequest',\n {\n id: suggestedAssetMeta.id,\n origin: ORIGIN_METAMASK,\n type: ApprovalType.WatchAsset,\n requestData: {\n id: suggestedAssetMeta.id,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n asset: {\n address: suggestedAssetMeta.asset.address,\n decimals: suggestedAssetMeta.asset.decimals,\n symbol: suggestedAssetMeta.asset.symbol,\n image: suggestedAssetMeta.asset.image || null,\n },\n },\n },\n true,\n );\n }\n}\n\nexport default TokensController;\n"]}
|
|
1
|
+
{"version":3,"file":"TokensController.js","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { AddApprovalRequest } from '@metamask/approval-controller';\nimport type {\n BaseConfig,\n BaseState,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport contractsMap from '@metamask/contract-metadata';\nimport {\n toChecksumHexAddress,\n ERC721_INTERFACE_ID,\n ORIGIN_METAMASK,\n ApprovalType,\n ERC20,\n} from '@metamask/controller-utils';\nimport { abiERC721 } from '@metamask/metamask-eth-abis';\nimport type {\n NetworkClientId,\n NetworkController,\n NetworkState,\n} from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { AbortController as WhatwgAbortController } from 'abort-controller';\nimport { Mutex } from 'async-mutex';\nimport { EventEmitter } from 'events';\nimport { v1 as random } from 'uuid';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport {\n formatAggregatorNames,\n formatIconUrlWithProxy,\n validateTokenToWatch,\n} from './assetsUtil';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from './token-service';\nimport type {\n TokenListMap,\n TokenListState,\n TokenListToken,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\n\n/**\n * @type TokensConfig\n *\n * Tokens controller configuration\n * @property selectedAddress - Vault selected address\n */\nexport interface TokensConfig extends BaseConfig {\n selectedAddress: string;\n chainId: Hex;\n provider: any;\n}\n\n/**\n * @type SuggestedAssetMeta\n *\n * Suggested asset by EIP747 meta data\n * @property id - Generated UUID associated with this suggested asset\n * @property time - Timestamp associated with this this suggested asset\n * @property type - Type type this suggested asset\n * @property asset - Asset suggested object\n * @property interactingAddress - Account address that requested watch asset\n */\ntype SuggestedAssetMeta = {\n id: string;\n time: number;\n type: string;\n asset: Token;\n interactingAddress: string;\n};\n\n/**\n * @type TokensState\n *\n * Assets controller state\n * @property tokens - List of tokens associated with the active network and address pair\n * @property ignoredTokens - List of ignoredTokens associated with the active network and address pair\n * @property detectedTokens - List of detected tokens associated with the active network and address pair\n * @property allTokens - Object containing tokens by network and account\n * @property allIgnoredTokens - Object containing hidden/ignored tokens by network and account\n * @property allDetectedTokens - Object containing tokens detected with non-zero balances\n */\nexport interface TokensState extends BaseState {\n tokens: Token[];\n ignoredTokens: string[];\n detectedTokens: Token[];\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allIgnoredTokens: { [chainId: Hex]: { [key: string]: string[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n}\n\n/**\n * The name of the {@link TokensController}.\n */\nconst controllerName = 'TokensController';\n\n/**\n * The external actions available to the {@link TokensController}.\n */\ntype AllowedActions = AddApprovalRequest;\n\n/**\n * The messenger of the {@link TokensController}.\n */\nexport type TokensControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n AllowedActions,\n never,\n AllowedActions['type'],\n never\n>;\n\n/**\n * Controller that stores assets and exposes convenience methods\n */\nexport class TokensController extends BaseController<\n TokensConfig,\n TokensState\n> {\n private readonly mutex = new Mutex();\n\n private abortController: WhatwgAbortController;\n\n private readonly messagingSystem: TokensControllerMessenger;\n\n /**\n * Fetch metadata for a token.\n *\n * @param tokenAddress - The address of the token.\n * @returns The token metadata.\n */\n private async fetchTokenMetadata(\n tokenAddress: string,\n ): Promise<TokenListToken | undefined> {\n try {\n const token = await fetchTokenMetadata<TokenListToken>(\n this.config.chainId,\n tokenAddress,\n this.abortController.signal,\n );\n return token;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * EventEmitter instance used to listen to specific EIP747 events\n */\n hub = new EventEmitter();\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokensController';\n\n private readonly getERC20TokenName: AssetsContractController['getERC20TokenName'];\n\n private readonly getNetworkClientById: NetworkController['getNetworkClientById'];\n\n /**\n * Creates a TokensController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.\n * @param options.getERC20TokenName - Gets the ERC-20 token name.\n * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.\n * @param options.config - Initial options used to configure this controller.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messenger.\n */\n constructor({\n chainId: initialChainId,\n onPreferencesStateChange,\n onNetworkStateChange,\n onTokenListStateChange,\n getERC20TokenName,\n getNetworkClientById,\n config,\n state,\n messenger,\n }: {\n chainId: Hex;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n onTokenListStateChange: (\n listener: (tokenListState: TokenListState) => void,\n ) => void;\n getERC20TokenName: AssetsContractController['getERC20TokenName'];\n getNetworkClientById: NetworkController['getNetworkClientById'];\n config?: Partial<TokensConfig>;\n state?: Partial<TokensState>;\n messenger: TokensControllerMessenger;\n }) {\n super(config, state);\n\n this.defaultConfig = {\n selectedAddress: '',\n chainId: initialChainId,\n provider: undefined,\n ...config,\n };\n\n this.defaultState = {\n tokens: [],\n ignoredTokens: [],\n detectedTokens: [],\n allTokens: {},\n allIgnoredTokens: {},\n allDetectedTokens: {},\n ...state,\n };\n\n this.initialize();\n this.abortController = new WhatwgAbortController();\n this.getERC20TokenName = getERC20TokenName;\n this.getNetworkClientById = getNetworkClientById;\n\n this.messagingSystem = messenger;\n\n onPreferencesStateChange(({ selectedAddress }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = this.config;\n this.configure({ selectedAddress });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { selectedAddress } = this.config;\n const { chainId } = providerConfig;\n this.abortController.abort();\n this.abortController = new WhatwgAbortController();\n this.configure({ chainId });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onTokenListStateChange(({ tokenList }) => {\n const { tokens } = this.state;\n if (tokens.length && !tokens[0].name) {\n this.updateTokensAttribute(tokenList, 'name');\n }\n });\n }\n\n /**\n * Adds a token to the stored token list.\n *\n * @param options - The method argument object.\n * @param options.address - Hex address of the token contract.\n * @param options.symbol - Symbol of the token.\n * @param options.decimals - Number of decimals the token uses.\n * @param options.name - Name of the token.\n * @param options.image - Image of the token.\n * @param options.interactingAddress - The address of the account to add a token to.\n * @param options.networkClientId - Network Client ID.\n * @returns Current token list.\n */\n async addToken({\n address,\n symbol,\n decimals,\n name,\n image,\n interactingAddress,\n networkClientId,\n }: {\n address: string;\n symbol: string;\n decimals: number;\n name?: string;\n image?: string;\n interactingAddress?: string;\n networkClientId?: NetworkClientId;\n }): Promise<Token[]> {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId, selectedAddress } = this.config;\n let currentChainId = chainId;\n if (networkClientId) {\n currentChainId =\n this.getNetworkClientById(networkClientId).configuration.chainId;\n }\n\n const accountAddress = interactingAddress || selectedAddress;\n const isInteractingWithWalletAccount = accountAddress === selectedAddress;\n const releaseLock = await this.mutex.acquire();\n\n try {\n address = toChecksumHexAddress(address);\n const tokens = allTokens[currentChainId]?.[accountAddress] || [];\n const ignoredTokens =\n allIgnoredTokens[currentChainId]?.[accountAddress] || [];\n const detectedTokens =\n allDetectedTokens[currentChainId]?.[accountAddress] || [];\n const newTokens: Token[] = [...tokens];\n const [isERC721, tokenMetadata] = await Promise.all([\n this._detectIsERC721(address, networkClientId),\n this.fetchTokenMetadata(address),\n ]);\n if (!networkClientId && currentChainId !== this.config.chainId) {\n throw new Error(\n 'TokensController Error: Switched networks while adding token',\n );\n }\n const newEntry: Token = {\n address,\n symbol,\n decimals,\n image:\n image ||\n formatIconUrlWithProxy({\n chainId: currentChainId,\n tokenAddress: address,\n }),\n isERC721,\n aggregators: formatAggregatorNames(tokenMetadata?.aggregators || []),\n name,\n };\n const previousEntry = newTokens.find(\n (token) => token.address.toLowerCase() === address.toLowerCase(),\n );\n if (previousEntry) {\n const previousIndex = newTokens.indexOf(previousEntry);\n newTokens[previousIndex] = newEntry;\n } else {\n newTokens.push(newEntry);\n }\n\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => tokenAddress.toLowerCase() !== address.toLowerCase(),\n );\n const newDetectedTokens = detectedTokens.filter(\n (token) => token.address.toLowerCase() !== address.toLowerCase(),\n );\n\n const { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens } =\n this._getNewAllTokensState({\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n interactingAddress: accountAddress,\n interactingChainId: currentChainId,\n });\n\n let newState: Partial<TokensState> = {\n allTokens: newAllTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n };\n\n // Only update active tokens if user is interacting with their active wallet account.\n if (isInteractingWithWalletAccount) {\n newState = {\n ...newState,\n tokens: newTokens,\n ignoredTokens: newIgnoredTokens,\n detectedTokens: newDetectedTokens,\n };\n }\n\n this.update(newState);\n return newTokens;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Add a batch of tokens.\n *\n * @param tokensToImport - Array of tokens to import.\n * @param networkClientId - Optional network client ID used to determine interacting chain ID.\n */\n async addTokens(tokensToImport: Token[], networkClientId?: NetworkClientId) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const importedTokensMap: { [key: string]: true } = {};\n // Used later to dedupe imported tokens\n const newTokensMap = tokens.reduce((output, current) => {\n output[current.address] = current;\n return output;\n }, {} as { [address: string]: Token });\n try {\n tokensToImport.forEach((tokenToAdd) => {\n const { address, symbol, decimals, image, aggregators, name } =\n tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const formattedToken: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n aggregators,\n name,\n };\n newTokensMap[address] = formattedToken;\n importedTokensMap[address.toLowerCase()] = true;\n return formattedToken;\n });\n const newTokens = Object.values(newTokensMap);\n\n const newDetectedTokens = detectedTokens.filter(\n (token) => !importedTokensMap[token.address.toLowerCase()],\n );\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => !newTokensMap[tokenAddress.toLowerCase()],\n );\n\n let interactingChainId;\n if (networkClientId) {\n interactingChainId =\n this.getNetworkClientById(networkClientId).configuration.chainId;\n }\n\n const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } =\n this._getNewAllTokensState({\n newTokens,\n newDetectedTokens,\n newIgnoredTokens,\n interactingChainId,\n });\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n ignoredTokens: newIgnoredTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Ignore a batch of tokens.\n *\n * @param tokenAddressesToIgnore - Array of token addresses to ignore.\n */\n ignoreTokens(tokenAddressesToIgnore: string[]) {\n const { ignoredTokens, detectedTokens, tokens } = this.state;\n const ignoredTokensMap: { [key: string]: true } = {};\n let newIgnoredTokens: string[] = [...ignoredTokens];\n\n const checksummedTokenAddresses = tokenAddressesToIgnore.map((address) => {\n const checksumAddress = toChecksumHexAddress(address);\n ignoredTokensMap[address.toLowerCase()] = true;\n return checksumAddress;\n });\n newIgnoredTokens = [...ignoredTokens, ...checksummedTokenAddresses];\n const newDetectedTokens = detectedTokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n const newTokens = tokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n\n const { newAllIgnoredTokens, newAllDetectedTokens, newAllTokens } =\n this._getNewAllTokensState({\n newIgnoredTokens,\n newDetectedTokens,\n newTokens,\n });\n\n this.update({\n ignoredTokens: newIgnoredTokens,\n tokens: newTokens,\n detectedTokens: newDetectedTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n allTokens: newAllTokens,\n });\n }\n\n /**\n * Adds a batch of detected tokens to the stored token list.\n *\n * @param incomingDetectedTokens - Array of detected tokens to be added or updated.\n * @param detectionDetails - An object containing the chain ID and address of the currently selected network on which the incomingDetectedTokens were detected.\n * @param detectionDetails.selectedAddress - the account address on which the incomingDetectedTokens were detected.\n * @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.\n */\n async addDetectedTokens(\n incomingDetectedTokens: Token[],\n detectionDetails?: { selectedAddress: string; chainId: Hex },\n ) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const newTokens: Token[] = [...tokens];\n let newDetectedTokens: Token[] = [...detectedTokens];\n\n try {\n incomingDetectedTokens.forEach((tokenToAdd) => {\n const {\n address,\n symbol,\n decimals,\n image,\n aggregators,\n isERC721,\n name,\n } = tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const newEntry: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n isERC721,\n aggregators,\n name,\n };\n const previousImportedEntry = newTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousImportedEntry) {\n // Update existing data of imported token\n const previousImportedIndex = newTokens.indexOf(\n previousImportedEntry,\n );\n newTokens[previousImportedIndex] = newEntry;\n } else {\n const ignoredTokenIndex = ignoredTokens.indexOf(address);\n if (ignoredTokenIndex === -1) {\n // Add detected token\n const previousDetectedEntry = newDetectedTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousDetectedEntry) {\n const previousDetectedIndex = newDetectedTokens.indexOf(\n previousDetectedEntry,\n );\n newDetectedTokens[previousDetectedIndex] = newEntry;\n } else {\n newDetectedTokens.push(newEntry);\n }\n }\n }\n });\n\n const {\n selectedAddress: interactingAddress,\n chainId: interactingChainId,\n } = detectionDetails || {};\n\n const { newAllTokens, newAllDetectedTokens } = this._getNewAllTokensState(\n {\n newTokens,\n newDetectedTokens,\n interactingAddress,\n interactingChainId,\n },\n );\n\n const { chainId, selectedAddress } = this.config;\n // if the newly added detectedTokens were detected on (and therefore added to) a different chainId/selectedAddress than the currently configured combo\n // the newDetectedTokens (which should contain the detectedTokens on the current chainId/address combo) needs to be repointed to the current chainId/address pair\n // if the detectedTokens were detected on the current chainId/address then this won't change anything.\n newDetectedTokens =\n newAllDetectedTokens?.[chainId]?.[selectedAddress] || [];\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Adds isERC721 field to token object. This is called when a user attempts to add tokens that\n * were previously added which do not yet had isERC721 field.\n *\n * @param tokenAddress - The contract address of the token requiring the isERC721 field added.\n * @returns The new token object with the added isERC721 field.\n */\n async updateTokenType(tokenAddress: string) {\n const isERC721 = await this._detectIsERC721(tokenAddress);\n const { tokens } = this.state;\n const tokenIndex = tokens.findIndex((token) => {\n return token.address.toLowerCase() === tokenAddress.toLowerCase();\n });\n tokens[tokenIndex].isERC721 = isERC721;\n this.update({ tokens });\n return tokens[tokenIndex];\n }\n\n /**\n * This is a function that updates the tokens name for the tokens name if it is not defined.\n *\n * @param tokenList - Represents the fetched token list from service API\n * @param tokenAttribute - Represents the token attribute that we want to update on the token list\n */\n private updateTokensAttribute(\n tokenList: TokenListMap,\n tokenAttribute: keyof Token & keyof TokenListToken,\n ) {\n const { tokens } = this.state;\n\n const newTokens = tokens.map((token) => {\n const newToken = tokenList[token.address.toLowerCase()];\n\n return !token[tokenAttribute] && newToken?.[tokenAttribute]\n ? { ...token, [tokenAttribute]: newToken[tokenAttribute] }\n : { ...token };\n });\n\n this.update({ tokens: newTokens });\n }\n\n /**\n * Detects whether or not a token is ERC-721 compatible.\n *\n * @param tokenAddress - The token contract address.\n * @param networkClientId - Optional network client ID to fetch contract info with.\n * @returns A boolean indicating whether the token address passed in supports the EIP-721\n * interface.\n */\n async _detectIsERC721(\n tokenAddress: string,\n networkClientId?: NetworkClientId,\n ) {\n const checksumAddress = toChecksumHexAddress(tokenAddress);\n // if this token is already in our contract metadata map we don't need\n // to check against the contract\n if (contractsMap[checksumAddress]?.erc721 === true) {\n return Promise.resolve(true);\n } else if (contractsMap[checksumAddress]?.erc20 === true) {\n return Promise.resolve(false);\n }\n\n const tokenContract = this._createEthersContract(\n tokenAddress,\n abiERC721,\n networkClientId,\n );\n try {\n return await tokenContract.supportsInterface(ERC721_INTERFACE_ID);\n } catch (error: any) {\n // currently we see a variety of errors across different networks when\n // token contracts are not ERC721 compatible. We need to figure out a better\n // way of differentiating token interface types but for now if we get an error\n // we have to assume the token is not ERC721 compatible.\n return false;\n }\n }\n\n _createEthersContract(\n tokenAddress: string,\n abi: string,\n networkClientId?: NetworkClientId,\n ): Contract {\n const provider = networkClientId\n ? this.getNetworkClientById(networkClientId).provider\n : this.config?.provider;\n\n const web3provider = new Web3Provider(provider);\n const tokenContract = new Contract(tokenAddress, abi, web3provider);\n return tokenContract;\n }\n\n _generateRandomId(): string {\n return random();\n }\n\n /**\n * Adds a new suggestedAsset to the list of watched assets.\n * Parameters will be validated according to the asset type being watched.\n *\n * @param options - The method options.\n * @param options.asset - The asset to be watched. For now only ERC20 tokens are accepted.\n * @param options.type - The asset type.\n * @param options.interactingAddress - The address of the account that is requesting to watch the asset.\n * @param options.networkClientId - Network Client ID.\n * @returns Object containing a Promise resolving to the suggestedAsset address if accepted.\n */\n async watchAsset({\n asset,\n type,\n interactingAddress,\n networkClientId,\n }: {\n asset: Token;\n type: string;\n interactingAddress?: string;\n networkClientId?: NetworkClientId;\n }): Promise<void> {\n if (type !== ERC20) {\n throw new Error(`Asset of type ${type} not supported`);\n }\n\n const { selectedAddress } = this.config;\n\n const suggestedAssetMeta: SuggestedAssetMeta = {\n asset,\n id: this._generateRandomId(),\n time: Date.now(),\n type,\n interactingAddress: interactingAddress || selectedAddress,\n };\n\n validateTokenToWatch(asset);\n\n await this._requestApproval(suggestedAssetMeta);\n\n let name;\n try {\n name = await this.getERC20TokenName(asset.address, networkClientId);\n } catch (error) {\n name = undefined;\n }\n\n const { address, symbol, decimals, image } = asset;\n await this.addToken({\n address,\n symbol,\n decimals,\n name,\n image,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n networkClientId,\n });\n }\n\n /**\n * Takes a new tokens and ignoredTokens array for the current network/account combination\n * and returns new allTokens and allIgnoredTokens state to update to.\n *\n * @param params - Object that holds token params.\n * @param params.newTokens - The new tokens to set for the current network and selected account.\n * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.\n * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.\n * @param params.interactingAddress - The account address to use to store the tokens.\n * @param params.interactingChainId - The chainId to use to store the tokens.\n * @returns The updated `allTokens` and `allIgnoredTokens` state.\n */\n _getNewAllTokensState(params: {\n newTokens?: Token[];\n newIgnoredTokens?: string[];\n newDetectedTokens?: Token[];\n interactingAddress?: string;\n interactingChainId?: Hex;\n }) {\n const {\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n interactingAddress,\n interactingChainId,\n } = params;\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId, selectedAddress } = this.config;\n\n const userAddressToAddTokens = interactingAddress ?? selectedAddress;\n const chainIdToAddTokens = interactingChainId ?? chainId;\n\n let newAllTokens = allTokens;\n if (\n newTokens?.length ||\n (newTokens &&\n allTokens &&\n allTokens[chainIdToAddTokens] &&\n allTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkTokens = allTokens[chainIdToAddTokens];\n const newNetworkTokens = {\n ...networkTokens,\n ...{ [userAddressToAddTokens]: newTokens },\n };\n newAllTokens = {\n ...allTokens,\n ...{ [chainIdToAddTokens]: newNetworkTokens },\n };\n }\n\n let newAllIgnoredTokens = allIgnoredTokens;\n if (\n newIgnoredTokens?.length ||\n (newIgnoredTokens &&\n allIgnoredTokens &&\n allIgnoredTokens[chainIdToAddTokens] &&\n allIgnoredTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkIgnoredTokens = allIgnoredTokens[chainIdToAddTokens];\n const newIgnoredNetworkTokens = {\n ...networkIgnoredTokens,\n ...{ [userAddressToAddTokens]: newIgnoredTokens },\n };\n newAllIgnoredTokens = {\n ...allIgnoredTokens,\n ...{ [chainIdToAddTokens]: newIgnoredNetworkTokens },\n };\n }\n\n let newAllDetectedTokens = allDetectedTokens;\n if (\n newDetectedTokens?.length ||\n (newDetectedTokens &&\n allDetectedTokens &&\n allDetectedTokens[chainIdToAddTokens] &&\n allDetectedTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkDetectedTokens = allDetectedTokens[chainIdToAddTokens];\n const newDetectedNetworkTokens = {\n ...networkDetectedTokens,\n ...{ [userAddressToAddTokens]: newDetectedTokens },\n };\n newAllDetectedTokens = {\n ...allDetectedTokens,\n ...{ [chainIdToAddTokens]: newDetectedNetworkTokens },\n };\n }\n return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };\n }\n\n /**\n * Removes all tokens from the ignored list.\n */\n clearIgnoredTokens() {\n this.update({ ignoredTokens: [], allIgnoredTokens: {} });\n }\n\n async _requestApproval(suggestedAssetMeta: SuggestedAssetMeta) {\n return this.messagingSystem.call(\n 'ApprovalController:addRequest',\n {\n id: suggestedAssetMeta.id,\n origin: ORIGIN_METAMASK,\n type: ApprovalType.WatchAsset,\n requestData: {\n id: suggestedAssetMeta.id,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n asset: {\n address: suggestedAssetMeta.asset.address,\n decimals: suggestedAssetMeta.asset.decimals,\n symbol: suggestedAssetMeta.asset.symbol,\n image: suggestedAssetMeta.asset.image || null,\n },\n },\n },\n true,\n );\n }\n}\n\nexport default TokensController;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask/assets-controllers",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MetaMask",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"@metamask/approval-controller": "^3.5.1",
|
|
37
37
|
"@metamask/base-controller": "^3.2.1",
|
|
38
38
|
"@metamask/contract-metadata": "^2.3.1",
|
|
39
|
-
"@metamask/controller-utils": "^
|
|
39
|
+
"@metamask/controller-utils": "^5.0.0",
|
|
40
40
|
"@metamask/eth-query": "^3.0.1",
|
|
41
41
|
"@metamask/metamask-eth-abis": "3.0.0",
|
|
42
|
-
"@metamask/network-controller": "^
|
|
43
|
-
"@metamask/preferences-controller": "^4.4.
|
|
42
|
+
"@metamask/network-controller": "^13.0.0",
|
|
43
|
+
"@metamask/preferences-controller": "^4.4.1",
|
|
44
44
|
"@metamask/rpc-errors": "^5.1.1",
|
|
45
45
|
"@metamask/utils": "^6.2.0",
|
|
46
46
|
"@types/uuid": "^8.3.0",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@metamask/approval-controller": "^3.5.1",
|
|
72
|
-
"@metamask/network-controller": "^
|
|
73
|
-
"@metamask/preferences-controller": "^4.4.
|
|
72
|
+
"@metamask/network-controller": "^13.0.0",
|
|
73
|
+
"@metamask/preferences-controller": "^4.4.1"
|
|
74
74
|
},
|
|
75
75
|
"engines": {
|
|
76
76
|
"node": ">=16.0.0"
|