@metamask/assets-controllers 12.0.0 → 14.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 +37 -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/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts +1 -1
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts.map +1 -1
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.d.ts +1 -1
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.d.ts.map +1 -1
- package/dist/TokenListController.d.ts.map +1 -1
- package/dist/TokenListController.js +2 -3
- package/dist/TokenListController.js.map +1 -1
- package/dist/TokensController.d.ts +33 -18
- package/dist/TokensController.d.ts.map +1 -1
- package/dist/TokensController.js +55 -32
- package/dist/TokensController.js.map +1 -1
- package/package.json +13 -14
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [14.0.0]
|
|
10
|
+
### Changed
|
|
11
|
+
- Update TypeScript to v4.8.x ([#1718](https://github.com/MetaMask/core/pull/1718))
|
|
12
|
+
- Update `@metamask/rpc-errors` to `^6.0.0` ([#1690](https://github.com/MetaMask/core/pull/1690))
|
|
13
|
+
|
|
14
|
+
### Removed
|
|
15
|
+
- **BREAKING:** Remove AbortController polyfill
|
|
16
|
+
- This package now assumes that the AbortController global exists
|
|
17
|
+
|
|
18
|
+
## [13.0.0]
|
|
19
|
+
### Changed
|
|
20
|
+
- **BREAKING**: `TokensController` now expects `getNetworkClientById` in constructor options ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
21
|
+
- **BREAKING**: `TokensController.addToken` now accepts a single options object ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
22
|
+
```
|
|
23
|
+
{
|
|
24
|
+
address: string;
|
|
25
|
+
symbol: string;
|
|
26
|
+
decimals: number;
|
|
27
|
+
name?: string;
|
|
28
|
+
image?: string;
|
|
29
|
+
interactingAddress?: string;
|
|
30
|
+
networkClientId?: NetworkClientId;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
- **BREAKING**: Bump peer dependency on `@metamask/network-controller` to ^13.0.0 ([#1633](https://github.com/MetaMask/core/pull/1633))
|
|
34
|
+
- **CHANGED**: `TokensController.addToken` will use the chain ID value derived from state for `networkClientId` if provided ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
35
|
+
- **CHANGED**: `TokensController.addTokens` now accepts an optional `networkClientId` as the last parameter ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
36
|
+
- **CHANGED**: `TokensController.addTokens` will use the chain ID value derived from state for `networkClientId` if provided ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
37
|
+
- **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))
|
|
38
|
+
- Bump dependency on `@metamask/controller-utils` to ^5.0.0 ([#1633](https://github.com/MetaMask/core/pull/1633))
|
|
39
|
+
- Bump dependency on `@metamask/preferences-controller` to ^4.4.1 ([#1676](https://github.com/MetaMask/core/pull/1676))
|
|
40
|
+
|
|
9
41
|
## [12.0.0]
|
|
10
42
|
### Added
|
|
11
43
|
- Add `AssetsContractController` methods `getProvider`, `getChainId`, `getERC721Standard`, and `getERC1155Standard` ([#1638](https://github.com/MetaMask/core/pull/1638))
|
|
@@ -78,7 +110,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
78
110
|
- The `getERC20TokenName` method is used to get the token name for tokens added via `wallet_watchAsset`
|
|
79
111
|
- 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
112
|
- **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
|
|
113
|
+
- The fourth and fifth positional parameters (`image` and `interactingAddress`) have been replaced by an `options` object
|
|
82
114
|
- The new options parameter includes the `image` and `interactingAddress` properties, and a new `name` property
|
|
83
115
|
- The token detection controller now sets the token name when new tokens are detected ([#1127](https://github.com/MetaMask/core/pull/1127))
|
|
84
116
|
- The `Token` type now includes an optional `name` field ([#1127](https://github.com/MetaMask/core/pull/1127))
|
|
@@ -157,7 +189,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
157
189
|
- **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
190
|
- **BREAKING:** Remove the `SuggestedAssetMeta` and `SuggestedAssetMetaBase` types from the token controller ([#1268](https://github.com/MetaMask/core/pull/1268))
|
|
159
191
|
- **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
|
|
192
|
+
- Suggested assets can be accepted or rejected using the approval controller instead
|
|
161
193
|
|
|
162
194
|
## [7.0.0]
|
|
163
195
|
### Changed
|
|
@@ -248,7 +280,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
248
280
|
### Changed
|
|
249
281
|
- Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/core/pull/845))
|
|
250
282
|
|
|
251
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@
|
|
283
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@14.0.0...HEAD
|
|
284
|
+
[14.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@13.0.0...@metamask/assets-controllers@14.0.0
|
|
285
|
+
[13.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@12.0.0...@metamask/assets-controllers@13.0.0
|
|
252
286
|
[12.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@11.1.0...@metamask/assets-controllers@12.0.0
|
|
253
287
|
[11.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@11.0.1...@metamask/assets-controllers@11.1.0
|
|
254
288
|
[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":"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;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,GAAG,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,kBAAkB,EAClB,SAAS,CACV;IACC,OAAO,CAAC,UAAU,CAAC,CAAgC;IAEnD,OAAO,CAAC,cAAc;YAUR,YAAY;IAyB1B;;OAEG;IACM,IAAI,SAA4B;IAEzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA2B;IAE5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IAEjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiB;IAE7C;;;;;;;;;;;;;OAaG;gBAED,EACE,OAAO,EAAE,cAAc,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,MAAM,EACN,WAAW,GACZ,EAAE;QACD,OAAO,EAAE,GAAG,CAAC;QACb,iBAAiB,EAAE,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,QAAQ,KAAK,IAAI,KAAK,IAAI,CAAC;QACrE,wBAAwB,EAAE,CACxB,QAAQ,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,KACnD,IAAI,CAAC;QACV,oBAAoB,EAAE,CACpB,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,KAC3C,IAAI,CAAC;QACV,gBAAgB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;QAC3C,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChC,WAAW,EAAE,MAAM,QAAQ,CAAC;KAC7B,EACD,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACpC,KAAK,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IAwC5B;;OAEG;IACG,KAAK;IAQX;;OAEG;IACH,IAAI;IAIJ,OAAO,CAAC,WAAW;IAMnB;;;;OAIG;YACW,YAAY;IAS1B;;;;OAIG;IACH,SAAS,QAAO,OAAO,CAA4C;IAEnE;;;OAGG;IACG,UAAU;CAkFjB;AAED,eAAe,sBAAsB,CAAC"}
|
|
@@ -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"]}
|
|
@@ -70,7 +70,7 @@ export declare class ERC1155Standard {
|
|
|
70
70
|
* @param tokenId - tokenId of a given token in the contract.
|
|
71
71
|
* @returns Promise resolving an object containing the standard, tokenURI, symbol and name of the given contract/tokenId pair.
|
|
72
72
|
*/
|
|
73
|
-
getDetails: (address: string, ipfsGateway: string, tokenId?: string
|
|
73
|
+
getDetails: (address: string, ipfsGateway: string, tokenId?: string) => Promise<{
|
|
74
74
|
standard: string;
|
|
75
75
|
tokenURI: string | undefined;
|
|
76
76
|
image: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ERC1155Standard.d.ts","sourceRoot":"","sources":["../../../../src/Standards/NftStandards/ERC1155/ERC1155Standard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAS7D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAI1C,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAIlC;;;;;OAKG;IACH,oCAAoC,YACzB,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,sCAAsC,YAC3B,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,iCAAiC,YACtB,MAAM,KACd,QAAQ,OAAO,CAAC,CAEjB;IAEF;;;;;;OAMG;IACH,WAAW,YAAmB,MAAM,WAAW,MAAM,KAAG,QAAQ,MAAM,CAAC,CAGrE;IAEF;;;;;;;OAOG;IACH,YAAY,oBACO,MAAM,WACd,MAAM,WACN,MAAM,KACd,QAAQ,EAAE,CAAC,CAIZ;IAEF;;;;;;;;;;;OAWG;IACH,cAAc,aACF,MAAM,QACV,MAAM,MACR,MAAM,MACN,MAAM,SACH,MAAM,KACZ,QAAQ,IAAI,CAAC,CAmBd;IAEF;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAMxC;IAEF;;;;;;;OAOG;IACH,UAAU,YACC,MAAM,eACF,MAAM;
|
|
1
|
+
{"version":3,"file":"ERC1155Standard.d.ts","sourceRoot":"","sources":["../../../../src/Standards/NftStandards/ERC1155/ERC1155Standard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAS7D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAI1C,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAIlC;;;;;OAKG;IACH,oCAAoC,YACzB,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,sCAAsC,YAC3B,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,iCAAiC,YACtB,MAAM,KACd,QAAQ,OAAO,CAAC,CAEjB;IAEF;;;;;;OAMG;IACH,WAAW,YAAmB,MAAM,WAAW,MAAM,KAAG,QAAQ,MAAM,CAAC,CAGrE;IAEF;;;;;;;OAOG;IACH,YAAY,oBACO,MAAM,WACd,MAAM,WACN,MAAM,KACd,QAAQ,EAAE,CAAC,CAIZ;IAEF;;;;;;;;;;;OAWG;IACH,cAAc,aACF,MAAM,QACV,MAAM,MACR,MAAM,MACN,MAAM,SACH,MAAM,KACZ,QAAQ,IAAI,CAAC,CAmBd;IAEF;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAMxC;IAEF;;;;;;;OAOG;IACH,UAAU,YACC,MAAM,eACF,MAAM,YACT,MAAM;kBAEN,MAAM;kBACN,MAAM,GAAG,SAAS;eACrB,MAAM,GAAG,SAAS;OAiCzB;CACH"}
|
|
@@ -78,7 +78,7 @@ export declare class ERC721Standard {
|
|
|
78
78
|
* @param tokenId - tokenId of a given token in the contract.
|
|
79
79
|
* @returns Promise resolving an object containing the standard, tokenURI, symbol and name of the given contract/tokenId pair.
|
|
80
80
|
*/
|
|
81
|
-
getDetails: (address: string, ipfsGateway: string, tokenId?: string
|
|
81
|
+
getDetails: (address: string, ipfsGateway: string, tokenId?: string) => Promise<{
|
|
82
82
|
standard: string;
|
|
83
83
|
tokenURI: string | undefined;
|
|
84
84
|
symbol: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ERC721Standard.d.ts","sourceRoot":"","sources":["../../../../src/Standards/NftStandards/ERC721/ERC721Standard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAY7D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAIlC;;;;;OAKG;IACH,iCAAiC,YACtB,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,mCAAmC,YACxB,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,gCAAgC,YACrB,MAAM,KACd,QAAQ,OAAO,CAAC,CAEjB;IAEF;;;;;;;OAOG;IACH,aAAa,YACF,MAAM,mBACE,MAAM,SAChB,MAAM,KACZ,QAAQ,MAAM,CAAC,CAGhB;IAEF;;;;;;OAMG;IACH,WAAW,YAAmB,MAAM,WAAW,MAAM,KAAG,QAAQ,MAAM,CAAC,CASrE;IAEF;;;;;OAKG;IACH,YAAY,YAAmB,MAAM,KAAG,QAAQ,MAAM,CAAC,CAGrD;IAEF;;;;;OAKG;IACH,cAAc,YAAmB,MAAM,KAAG,QAAQ,MAAM,CAAC,CAGvD;IAEF;;;;;;OAMG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnE;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAcxC;IAEF;;;;;;;OAOG;IACH,UAAU,YACC,MAAM,eACF,MAAM;
|
|
1
|
+
{"version":3,"file":"ERC721Standard.d.ts","sourceRoot":"","sources":["../../../../src/Standards/NftStandards/ERC721/ERC721Standard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAY7D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAIlC;;;;;OAKG;IACH,iCAAiC,YACtB,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,mCAAmC,YACxB,MAAM,KACd,QAAQ,OAAO,CAAC,CAKjB;IAEF;;;;;OAKG;IACH,gCAAgC,YACrB,MAAM,KACd,QAAQ,OAAO,CAAC,CAEjB;IAEF;;;;;;;OAOG;IACH,aAAa,YACF,MAAM,mBACE,MAAM,SAChB,MAAM,KACZ,QAAQ,MAAM,CAAC,CAGhB;IAEF;;;;;;OAMG;IACH,WAAW,YAAmB,MAAM,WAAW,MAAM,KAAG,QAAQ,MAAM,CAAC,CASrE;IAEF;;;;;OAKG;IACH,YAAY,YAAmB,MAAM,KAAG,QAAQ,MAAM,CAAC,CAGrD;IAEF;;;;;OAKG;IACH,cAAc,YAAmB,MAAM,KAAG,QAAQ,MAAM,CAAC,CAGvD;IAEF;;;;;;OAMG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnE;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAcxC;IAEF;;;;;;;OAOG;IACH,UAAU,YACC,MAAM,eACF,MAAM,YACT,MAAM;kBAEN,MAAM;kBACN,MAAM,GAAG,SAAS;gBACpB,MAAM,GAAG,SAAS;cACpB,MAAM,GAAG,SAAS;eACjB,MAAM,GAAG,SAAS;OA+CzB;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenListController.d.ts","sourceRoot":"","sources":["../src/TokenListController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,KAAK,EACV,iCAAiC,EACjC,YAAY,EACb,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"TokenListController.d.ts","sourceRoot":"","sources":["../src/TokenListController.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
18
18
|
exports.TokenListController = void 0;
|
|
19
19
|
const base_controller_1 = require("@metamask/base-controller");
|
|
20
20
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
21
|
-
const abort_controller_1 = require("abort-controller");
|
|
22
21
|
const async_mutex_1 = require("async-mutex");
|
|
23
22
|
const assetsUtil_1 = require("./assetsUtil");
|
|
24
23
|
const token_service_1 = require("./token-service");
|
|
@@ -64,7 +63,7 @@ class TokenListController extends base_controller_1.BaseControllerV2 {
|
|
|
64
63
|
this.cacheRefreshThreshold = cacheRefreshThreshold;
|
|
65
64
|
this.chainId = chainId;
|
|
66
65
|
this.updatePreventPollingOnNetworkRestart(preventPollingOnNetworkRestart);
|
|
67
|
-
this.abortController = new
|
|
66
|
+
this.abortController = new AbortController();
|
|
68
67
|
if (onNetworkStateChange) {
|
|
69
68
|
onNetworkStateChange((networkControllerState) => __awaiter(this, void 0, void 0, function* () {
|
|
70
69
|
yield __classPrivateFieldGet(this, _TokenListController_instances, "m", _TokenListController_onNetworkControllerStateChange).call(this, networkControllerState);
|
|
@@ -228,7 +227,7 @@ _TokenListController_instances = new WeakSet(), _TokenListController_onNetworkCo
|
|
|
228
227
|
return __awaiter(this, void 0, void 0, function* () {
|
|
229
228
|
if (this.chainId !== networkControllerState.providerConfig.chainId) {
|
|
230
229
|
this.abortController.abort();
|
|
231
|
-
this.abortController = new
|
|
230
|
+
this.abortController = new AbortController();
|
|
232
231
|
this.chainId = networkControllerState.providerConfig.chainId;
|
|
233
232
|
if (this.state.preventPollingOnNetworkRestart) {
|
|
234
233
|
this.clearingTokenListData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenListController.js","sourceRoot":"","sources":["../src/TokenListController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport { BaseControllerV2 } from '@metamask/base-controller';\nimport { safelyExecute } from '@metamask/controller-utils';\nimport type {\n NetworkControllerStateChangeEvent,\n NetworkState,\n} from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\nimport { AbortController as WhatwgAbortController } from 'abort-controller';\nimport { Mutex } from 'async-mutex';\nimport type { Patch } from 'immer';\n\nimport {\n isTokenListSupportedForNetwork,\n formatAggregatorNames,\n formatIconUrlWithProxy,\n} from './assetsUtil';\nimport { fetchTokenList } from './token-service';\n\nconst DEFAULT_INTERVAL = 24 * 60 * 60 * 1000;\nconst DEFAULT_THRESHOLD = 24 * 60 * 60 * 1000;\n\nconst name = 'TokenListController';\n\nexport type TokenListToken = {\n name: string;\n symbol: string;\n decimals: number;\n address: string;\n occurrences: number;\n aggregators: string[];\n iconUrl: string;\n};\n\nexport type TokenListMap = Record<string, TokenListToken>;\n\ntype DataCache = {\n timestamp: number;\n data: TokenListMap;\n};\ntype TokensChainsCache = {\n [chainId: Hex]: DataCache;\n};\n\nexport type TokenListState = {\n tokenList: TokenListMap;\n tokensChainsCache: TokensChainsCache;\n preventPollingOnNetworkRestart: boolean;\n};\n\nexport type TokenListStateChange = {\n type: `${typeof name}:stateChange`;\n payload: [TokenListState, Patch[]];\n};\n\nexport type GetTokenListState = {\n type: `${typeof name}:getState`;\n handler: () => TokenListState;\n};\n\ntype TokenListMessenger = RestrictedControllerMessenger<\n typeof name,\n GetTokenListState,\n TokenListStateChange | NetworkControllerStateChangeEvent,\n never,\n TokenListStateChange['type'] | NetworkControllerStateChangeEvent['type']\n>;\n\nconst metadata = {\n tokenList: { persist: true, anonymous: true },\n tokensChainsCache: { persist: true, anonymous: true },\n preventPollingOnNetworkRestart: { persist: true, anonymous: true },\n};\n\nconst defaultState: TokenListState = {\n tokenList: {},\n tokensChainsCache: {},\n preventPollingOnNetworkRestart: false,\n};\n\n/**\n * Controller that passively polls on a set interval for the list of tokens from metaswaps api\n */\nexport class TokenListController extends BaseControllerV2<\n typeof name,\n TokenListState,\n TokenListMessenger\n> {\n private readonly mutex = new Mutex();\n\n private intervalId?: ReturnType<typeof setTimeout>;\n\n private readonly intervalDelay: number;\n\n private readonly cacheRefreshThreshold: number;\n\n private chainId: Hex;\n\n private abortController: WhatwgAbortController;\n\n /**\n * Creates a TokenListController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onNetworkStateChange - A function for registering an event handler for network state changes.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.cacheRefreshThreshold - The token cache expiry time, in milliseconds.\n * @param options.messenger - A restricted controller messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.preventPollingOnNetworkRestart - Determines whether to prevent poilling on network restart in extension.\n */\n constructor({\n chainId,\n preventPollingOnNetworkRestart = false,\n onNetworkStateChange,\n interval = DEFAULT_INTERVAL,\n cacheRefreshThreshold = DEFAULT_THRESHOLD,\n messenger,\n state,\n }: {\n chainId: Hex;\n preventPollingOnNetworkRestart?: boolean;\n onNetworkStateChange?: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n interval?: number;\n cacheRefreshThreshold?: number;\n messenger: TokenListMessenger;\n state?: Partial<TokenListState>;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.intervalDelay = interval;\n this.cacheRefreshThreshold = cacheRefreshThreshold;\n this.chainId = chainId;\n this.updatePreventPollingOnNetworkRestart(preventPollingOnNetworkRestart);\n this.abortController = new WhatwgAbortController();\n if (onNetworkStateChange) {\n onNetworkStateChange(async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n });\n } else {\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n },\n );\n }\n }\n\n /**\n * Updates state and restarts polling on changes to the network controller\n * state.\n *\n * @param networkControllerState - The updated network controller state.\n */\n async #onNetworkControllerStateChange(networkControllerState: NetworkState) {\n if (this.chainId !== networkControllerState.providerConfig.chainId) {\n this.abortController.abort();\n this.abortController = new WhatwgAbortController();\n this.chainId = networkControllerState.providerConfig.chainId;\n if (this.state.preventPollingOnNetworkRestart) {\n this.clearingTokenListData();\n } else {\n // Ensure tokenList is referencing data from correct network\n this.update(() => {\n return {\n ...this.state,\n tokenList: this.state.tokensChainsCache[this.chainId]?.data || {},\n };\n });\n await this.restart();\n }\n }\n }\n\n /**\n * Start polling for the token list.\n */\n async start() {\n if (!isTokenListSupportedForNetwork(this.chainId)) {\n return;\n }\n await this.startPolling();\n }\n\n /**\n * Restart polling for the token list.\n */\n async restart() {\n this.stopPolling();\n await this.startPolling();\n }\n\n /**\n * Stop polling for the token list.\n */\n stop() {\n this.stopPolling();\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopPolling();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n private async startPolling(): Promise<void> {\n await safelyExecute(() => this.fetchTokenList());\n this.intervalId = setInterval(async () => {\n await safelyExecute(() => this.fetchTokenList());\n }, this.intervalDelay);\n }\n\n /**\n * Fetching token list from the Token Service API.\n */\n async fetchTokenList(): Promise<void> {\n const releaseLock = await this.mutex.acquire();\n try {\n const { tokensChainsCache } = this.state;\n let tokenList: TokenListMap = {};\n const cachedTokens: TokenListMap = await safelyExecute(() =>\n this.fetchFromCache(),\n );\n if (cachedTokens) {\n // Use non-expired cached tokens\n tokenList = { ...cachedTokens };\n } else {\n // Fetch fresh token list\n const tokensFromAPI: TokenListToken[] = await safelyExecute(() =>\n fetchTokenList(this.chainId, this.abortController.signal),\n );\n\n if (!tokensFromAPI) {\n // Fallback to expired cached tokens\n tokenList = { ...(tokensChainsCache[this.chainId]?.data || {}) };\n\n this.update(() => {\n return {\n ...this.state,\n tokenList,\n tokensChainsCache,\n };\n });\n return;\n }\n // Filtering out tokens with less than 3 occurrences and native tokens\n const filteredTokenList = tokensFromAPI.filter(\n (token) =>\n token.occurrences &&\n token.occurrences >= 3 &&\n token.address !== '0x0000000000000000000000000000000000000000',\n );\n // Removing the tokens with symbol conflicts\n const symbolsList = filteredTokenList.map((token) => token.symbol);\n const duplicateSymbols = [\n ...new Set(\n symbolsList.filter(\n (symbol, index) => symbolsList.indexOf(symbol) !== index,\n ),\n ),\n ];\n const uniqueTokenList = filteredTokenList.filter(\n (token) => !duplicateSymbols.includes(token.symbol),\n );\n for (const token of uniqueTokenList) {\n const formattedToken: TokenListToken = {\n ...token,\n aggregators: formatAggregatorNames(token.aggregators),\n iconUrl: formatIconUrlWithProxy({\n chainId: this.chainId,\n tokenAddress: token.address,\n }),\n };\n tokenList[token.address] = formattedToken;\n }\n }\n const updatedTokensChainsCache: TokensChainsCache = {\n ...tokensChainsCache,\n [this.chainId]: {\n timestamp: Date.now(),\n data: tokenList,\n },\n };\n this.update(() => {\n return {\n ...this.state,\n tokenList,\n tokensChainsCache: updatedTokensChainsCache,\n };\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Checks if the Cache timestamp is valid,\n * if yes data in cache will be returned\n * otherwise null will be returned.\n *\n * @returns The cached data, or `null` if the cache was expired.\n */\n async fetchFromCache(): Promise<TokenListMap | null> {\n const { tokensChainsCache }: TokenListState = this.state;\n const dataCache = tokensChainsCache[this.chainId];\n const now = Date.now();\n if (\n dataCache?.data &&\n now - dataCache?.timestamp < this.cacheRefreshThreshold\n ) {\n return dataCache.data;\n }\n return null;\n }\n\n /**\n * Clearing tokenList and tokensChainsCache explicitly.\n */\n clearingTokenListData(): void {\n this.update(() => {\n return {\n ...this.state,\n tokenList: {},\n tokensChainsCache: {},\n };\n });\n }\n\n /**\n * Updates preventPollingOnNetworkRestart from extension.\n *\n * @param shouldPreventPolling - Determine whether to prevent polling on network change\n */\n updatePreventPollingOnNetworkRestart(shouldPreventPolling: boolean): void {\n this.update(() => {\n return {\n ...this.state,\n preventPollingOnNetworkRestart: shouldPreventPolling,\n };\n });\n }\n}\n\nexport default TokenListController;\n"]}
|
|
1
|
+
{"version":3,"file":"TokenListController.js","sourceRoot":"","sources":["../src/TokenListController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport { BaseControllerV2 } from '@metamask/base-controller';\nimport { safelyExecute } from '@metamask/controller-utils';\nimport type {\n NetworkControllerStateChangeEvent,\n NetworkState,\n} from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport type { Patch } from 'immer';\n\nimport {\n isTokenListSupportedForNetwork,\n formatAggregatorNames,\n formatIconUrlWithProxy,\n} from './assetsUtil';\nimport { fetchTokenList } from './token-service';\n\nconst DEFAULT_INTERVAL = 24 * 60 * 60 * 1000;\nconst DEFAULT_THRESHOLD = 24 * 60 * 60 * 1000;\n\nconst name = 'TokenListController';\n\nexport type TokenListToken = {\n name: string;\n symbol: string;\n decimals: number;\n address: string;\n occurrences: number;\n aggregators: string[];\n iconUrl: string;\n};\n\nexport type TokenListMap = Record<string, TokenListToken>;\n\ntype DataCache = {\n timestamp: number;\n data: TokenListMap;\n};\ntype TokensChainsCache = {\n [chainId: Hex]: DataCache;\n};\n\nexport type TokenListState = {\n tokenList: TokenListMap;\n tokensChainsCache: TokensChainsCache;\n preventPollingOnNetworkRestart: boolean;\n};\n\nexport type TokenListStateChange = {\n type: `${typeof name}:stateChange`;\n payload: [TokenListState, Patch[]];\n};\n\nexport type GetTokenListState = {\n type: `${typeof name}:getState`;\n handler: () => TokenListState;\n};\n\ntype TokenListMessenger = RestrictedControllerMessenger<\n typeof name,\n GetTokenListState,\n TokenListStateChange | NetworkControllerStateChangeEvent,\n never,\n TokenListStateChange['type'] | NetworkControllerStateChangeEvent['type']\n>;\n\nconst metadata = {\n tokenList: { persist: true, anonymous: true },\n tokensChainsCache: { persist: true, anonymous: true },\n preventPollingOnNetworkRestart: { persist: true, anonymous: true },\n};\n\nconst defaultState: TokenListState = {\n tokenList: {},\n tokensChainsCache: {},\n preventPollingOnNetworkRestart: false,\n};\n\n/**\n * Controller that passively polls on a set interval for the list of tokens from metaswaps api\n */\nexport class TokenListController extends BaseControllerV2<\n typeof name,\n TokenListState,\n TokenListMessenger\n> {\n private readonly mutex = new Mutex();\n\n private intervalId?: ReturnType<typeof setTimeout>;\n\n private readonly intervalDelay: number;\n\n private readonly cacheRefreshThreshold: number;\n\n private chainId: Hex;\n\n private abortController: AbortController;\n\n /**\n * Creates a TokenListController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onNetworkStateChange - A function for registering an event handler for network state changes.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.cacheRefreshThreshold - The token cache expiry time, in milliseconds.\n * @param options.messenger - A restricted controller messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.preventPollingOnNetworkRestart - Determines whether to prevent poilling on network restart in extension.\n */\n constructor({\n chainId,\n preventPollingOnNetworkRestart = false,\n onNetworkStateChange,\n interval = DEFAULT_INTERVAL,\n cacheRefreshThreshold = DEFAULT_THRESHOLD,\n messenger,\n state,\n }: {\n chainId: Hex;\n preventPollingOnNetworkRestart?: boolean;\n onNetworkStateChange?: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n interval?: number;\n cacheRefreshThreshold?: number;\n messenger: TokenListMessenger;\n state?: Partial<TokenListState>;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.intervalDelay = interval;\n this.cacheRefreshThreshold = cacheRefreshThreshold;\n this.chainId = chainId;\n this.updatePreventPollingOnNetworkRestart(preventPollingOnNetworkRestart);\n this.abortController = new AbortController();\n if (onNetworkStateChange) {\n onNetworkStateChange(async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n });\n } else {\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n },\n );\n }\n }\n\n /**\n * Updates state and restarts polling on changes to the network controller\n * state.\n *\n * @param networkControllerState - The updated network controller state.\n */\n async #onNetworkControllerStateChange(networkControllerState: NetworkState) {\n if (this.chainId !== networkControllerState.providerConfig.chainId) {\n this.abortController.abort();\n this.abortController = new AbortController();\n this.chainId = networkControllerState.providerConfig.chainId;\n if (this.state.preventPollingOnNetworkRestart) {\n this.clearingTokenListData();\n } else {\n // Ensure tokenList is referencing data from correct network\n this.update(() => {\n return {\n ...this.state,\n tokenList: this.state.tokensChainsCache[this.chainId]?.data || {},\n };\n });\n await this.restart();\n }\n }\n }\n\n /**\n * Start polling for the token list.\n */\n async start() {\n if (!isTokenListSupportedForNetwork(this.chainId)) {\n return;\n }\n await this.startPolling();\n }\n\n /**\n * Restart polling for the token list.\n */\n async restart() {\n this.stopPolling();\n await this.startPolling();\n }\n\n /**\n * Stop polling for the token list.\n */\n stop() {\n this.stopPolling();\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopPolling();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n private async startPolling(): Promise<void> {\n await safelyExecute(() => this.fetchTokenList());\n this.intervalId = setInterval(async () => {\n await safelyExecute(() => this.fetchTokenList());\n }, this.intervalDelay);\n }\n\n /**\n * Fetching token list from the Token Service API.\n */\n async fetchTokenList(): Promise<void> {\n const releaseLock = await this.mutex.acquire();\n try {\n const { tokensChainsCache } = this.state;\n let tokenList: TokenListMap = {};\n const cachedTokens: TokenListMap = await safelyExecute(() =>\n this.fetchFromCache(),\n );\n if (cachedTokens) {\n // Use non-expired cached tokens\n tokenList = { ...cachedTokens };\n } else {\n // Fetch fresh token list\n const tokensFromAPI: TokenListToken[] = await safelyExecute(() =>\n fetchTokenList(this.chainId, this.abortController.signal),\n );\n\n if (!tokensFromAPI) {\n // Fallback to expired cached tokens\n tokenList = { ...(tokensChainsCache[this.chainId]?.data || {}) };\n\n this.update(() => {\n return {\n ...this.state,\n tokenList,\n tokensChainsCache,\n };\n });\n return;\n }\n // Filtering out tokens with less than 3 occurrences and native tokens\n const filteredTokenList = tokensFromAPI.filter(\n (token) =>\n token.occurrences &&\n token.occurrences >= 3 &&\n token.address !== '0x0000000000000000000000000000000000000000',\n );\n // Removing the tokens with symbol conflicts\n const symbolsList = filteredTokenList.map((token) => token.symbol);\n const duplicateSymbols = [\n ...new Set(\n symbolsList.filter(\n (symbol, index) => symbolsList.indexOf(symbol) !== index,\n ),\n ),\n ];\n const uniqueTokenList = filteredTokenList.filter(\n (token) => !duplicateSymbols.includes(token.symbol),\n );\n for (const token of uniqueTokenList) {\n const formattedToken: TokenListToken = {\n ...token,\n aggregators: formatAggregatorNames(token.aggregators),\n iconUrl: formatIconUrlWithProxy({\n chainId: this.chainId,\n tokenAddress: token.address,\n }),\n };\n tokenList[token.address] = formattedToken;\n }\n }\n const updatedTokensChainsCache: TokensChainsCache = {\n ...tokensChainsCache,\n [this.chainId]: {\n timestamp: Date.now(),\n data: tokenList,\n },\n };\n this.update(() => {\n return {\n ...this.state,\n tokenList,\n tokensChainsCache: updatedTokensChainsCache,\n };\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Checks if the Cache timestamp is valid,\n * if yes data in cache will be returned\n * otherwise null will be returned.\n *\n * @returns The cached data, or `null` if the cache was expired.\n */\n async fetchFromCache(): Promise<TokenListMap | null> {\n const { tokensChainsCache }: TokenListState = this.state;\n const dataCache = tokensChainsCache[this.chainId];\n const now = Date.now();\n if (\n dataCache?.data &&\n now - dataCache?.timestamp < this.cacheRefreshThreshold\n ) {\n return dataCache.data;\n }\n return null;\n }\n\n /**\n * Clearing tokenList and tokensChainsCache explicitly.\n */\n clearingTokenListData(): void {\n this.update(() => {\n return {\n ...this.state,\n tokenList: {},\n tokensChainsCache: {},\n };\n });\n }\n\n /**\n * Updates preventPollingOnNetworkRestart from extension.\n *\n * @param shouldPreventPolling - Determine whether to prevent polling on network change\n */\n updatePreventPollingOnNetworkRestart(shouldPreventPolling: boolean): void {\n this.update(() => {\n return {\n ...this.state,\n preventPollingOnNetworkRestart: shouldPreventPolling,\n };\n });\n }\n}\n\nexport default TokenListController;\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
|
@@ -19,7 +19,6 @@ const base_controller_1 = require("@metamask/base-controller");
|
|
|
19
19
|
const contract_metadata_1 = __importDefault(require("@metamask/contract-metadata"));
|
|
20
20
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
21
21
|
const metamask_eth_abis_1 = require("@metamask/metamask-eth-abis");
|
|
22
|
-
const abort_controller_1 = require("abort-controller");
|
|
23
22
|
const async_mutex_1 = require("async-mutex");
|
|
24
23
|
const events_1 = require("events");
|
|
25
24
|
const uuid_1 = require("uuid");
|
|
@@ -42,11 +41,12 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
42
41
|
* @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
|
|
43
42
|
* @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.
|
|
44
43
|
* @param options.getERC20TokenName - Gets the ERC-20 token name.
|
|
44
|
+
* @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.
|
|
45
45
|
* @param options.config - Initial options used to configure this controller.
|
|
46
46
|
* @param options.state - Initial state to set on this controller.
|
|
47
47
|
* @param options.messenger - The controller messenger.
|
|
48
48
|
*/
|
|
49
|
-
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, onTokenListStateChange, getERC20TokenName, config, state, messenger, }) {
|
|
49
|
+
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, onTokenListStateChange, getERC20TokenName, getNetworkClientById, config, state, messenger, }) {
|
|
50
50
|
super(config, state);
|
|
51
51
|
this.mutex = new async_mutex_1.Mutex();
|
|
52
52
|
/**
|
|
@@ -60,8 +60,9 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
60
60
|
this.defaultConfig = Object.assign({ selectedAddress: '', chainId: initialChainId, provider: undefined }, config);
|
|
61
61
|
this.defaultState = Object.assign({ tokens: [], ignoredTokens: [], detectedTokens: [], allTokens: {}, allIgnoredTokens: {}, allDetectedTokens: {} }, state);
|
|
62
62
|
this.initialize();
|
|
63
|
-
this.abortController = new
|
|
63
|
+
this.abortController = new AbortController();
|
|
64
64
|
this.getERC20TokenName = getERC20TokenName;
|
|
65
|
+
this.getNetworkClientById = getNetworkClientById;
|
|
65
66
|
this.messagingSystem = messenger;
|
|
66
67
|
onPreferencesStateChange(({ selectedAddress }) => {
|
|
67
68
|
var _a, _b, _c;
|
|
@@ -80,9 +81,8 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
80
81
|
const { selectedAddress } = this.config;
|
|
81
82
|
const { chainId } = providerConfig;
|
|
82
83
|
this.abortController.abort();
|
|
83
|
-
this.abortController = new
|
|
84
|
+
this.abortController = new AbortController();
|
|
84
85
|
this.configure({ chainId });
|
|
85
|
-
this.ethersProvider = this._instantiateNewEthersProvider();
|
|
86
86
|
this.update({
|
|
87
87
|
tokens: ((_a = allTokens[chainId]) === null || _a === void 0 ? void 0 : _a[selectedAddress]) || [],
|
|
88
88
|
ignoredTokens: ((_b = allIgnoredTokens[chainId]) === null || _b === void 0 ? void 0 : _b[selectedAddress]) || [],
|
|
@@ -117,27 +117,29 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
117
117
|
}
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
|
-
_instantiateNewEthersProvider() {
|
|
121
|
-
var _a;
|
|
122
|
-
return new providers_1.Web3Provider((_a = this.config) === null || _a === void 0 ? void 0 : _a.provider);
|
|
123
|
-
}
|
|
124
120
|
/**
|
|
125
121
|
* Adds a token to the stored token list.
|
|
126
122
|
*
|
|
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
|
|
123
|
+
* @param options - The method argument object.
|
|
124
|
+
* @param options.address - Hex address of the token contract.
|
|
125
|
+
* @param options.symbol - Symbol of the token.
|
|
126
|
+
* @param options.decimals - Number of decimals the token uses.
|
|
127
|
+
* @param options.name - Name of the token.
|
|
128
|
+
* @param options.image - Image of the token.
|
|
133
129
|
* @param options.interactingAddress - The address of the account to add a token to.
|
|
130
|
+
* @param options.networkClientId - Network Client ID.
|
|
134
131
|
* @returns Current token list.
|
|
135
132
|
*/
|
|
136
|
-
addToken(address, symbol, decimals,
|
|
133
|
+
addToken({ address, symbol, decimals, name, image, interactingAddress, networkClientId, }) {
|
|
137
134
|
var _a, _b, _c;
|
|
138
135
|
return __awaiter(this, void 0, void 0, function* () {
|
|
139
136
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
140
|
-
const { chainId
|
|
137
|
+
const { chainId, selectedAddress } = this.config;
|
|
138
|
+
let currentChainId = chainId;
|
|
139
|
+
if (networkClientId) {
|
|
140
|
+
currentChainId =
|
|
141
|
+
this.getNetworkClientById(networkClientId).configuration.chainId;
|
|
142
|
+
}
|
|
141
143
|
const accountAddress = interactingAddress || selectedAddress;
|
|
142
144
|
const isInteractingWithWalletAccount = accountAddress === selectedAddress;
|
|
143
145
|
const releaseLock = yield this.mutex.acquire();
|
|
@@ -148,10 +150,10 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
148
150
|
const detectedTokens = ((_c = allDetectedTokens[currentChainId]) === null || _c === void 0 ? void 0 : _c[accountAddress]) || [];
|
|
149
151
|
const newTokens = [...tokens];
|
|
150
152
|
const [isERC721, tokenMetadata] = yield Promise.all([
|
|
151
|
-
this._detectIsERC721(address),
|
|
153
|
+
this._detectIsERC721(address, networkClientId),
|
|
152
154
|
this.fetchTokenMetadata(address),
|
|
153
155
|
]);
|
|
154
|
-
if (currentChainId !== this.config.chainId) {
|
|
156
|
+
if (!networkClientId && currentChainId !== this.config.chainId) {
|
|
155
157
|
throw new Error('TokensController Error: Switched networks while adding token');
|
|
156
158
|
}
|
|
157
159
|
const newEntry = {
|
|
@@ -160,7 +162,7 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
160
162
|
decimals,
|
|
161
163
|
image: image ||
|
|
162
164
|
(0, assetsUtil_1.formatIconUrlWithProxy)({
|
|
163
|
-
chainId:
|
|
165
|
+
chainId: currentChainId,
|
|
164
166
|
tokenAddress: address,
|
|
165
167
|
}),
|
|
166
168
|
isERC721,
|
|
@@ -182,6 +184,7 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
182
184
|
newIgnoredTokens,
|
|
183
185
|
newDetectedTokens,
|
|
184
186
|
interactingAddress: accountAddress,
|
|
187
|
+
interactingChainId: currentChainId,
|
|
185
188
|
});
|
|
186
189
|
let newState = {
|
|
187
190
|
allTokens: newAllTokens,
|
|
@@ -204,8 +207,9 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
204
207
|
* Add a batch of tokens.
|
|
205
208
|
*
|
|
206
209
|
* @param tokensToImport - Array of tokens to import.
|
|
210
|
+
* @param networkClientId - Optional network client ID used to determine interacting chain ID.
|
|
207
211
|
*/
|
|
208
|
-
addTokens(tokensToImport) {
|
|
212
|
+
addTokens(tokensToImport, networkClientId) {
|
|
209
213
|
return __awaiter(this, void 0, void 0, function* () {
|
|
210
214
|
const releaseLock = yield this.mutex.acquire();
|
|
211
215
|
const { tokens, detectedTokens, ignoredTokens } = this.state;
|
|
@@ -234,10 +238,16 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
234
238
|
const newTokens = Object.values(newTokensMap);
|
|
235
239
|
const newDetectedTokens = detectedTokens.filter((token) => !importedTokensMap[token.address.toLowerCase()]);
|
|
236
240
|
const newIgnoredTokens = ignoredTokens.filter((tokenAddress) => !newTokensMap[tokenAddress.toLowerCase()]);
|
|
241
|
+
let interactingChainId;
|
|
242
|
+
if (networkClientId) {
|
|
243
|
+
interactingChainId =
|
|
244
|
+
this.getNetworkClientById(networkClientId).configuration.chainId;
|
|
245
|
+
}
|
|
237
246
|
const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } = this._getNewAllTokensState({
|
|
238
247
|
newTokens,
|
|
239
248
|
newDetectedTokens,
|
|
240
249
|
newIgnoredTokens,
|
|
250
|
+
interactingChainId,
|
|
241
251
|
});
|
|
242
252
|
this.update({
|
|
243
253
|
tokens: newTokens,
|
|
@@ -396,10 +406,11 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
396
406
|
* Detects whether or not a token is ERC-721 compatible.
|
|
397
407
|
*
|
|
398
408
|
* @param tokenAddress - The token contract address.
|
|
409
|
+
* @param networkClientId - Optional network client ID to fetch contract info with.
|
|
399
410
|
* @returns A boolean indicating whether the token address passed in supports the EIP-721
|
|
400
411
|
* interface.
|
|
401
412
|
*/
|
|
402
|
-
_detectIsERC721(tokenAddress) {
|
|
413
|
+
_detectIsERC721(tokenAddress, networkClientId) {
|
|
403
414
|
var _a, _b;
|
|
404
415
|
return __awaiter(this, void 0, void 0, function* () {
|
|
405
416
|
const checksumAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress);
|
|
@@ -411,7 +422,7 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
411
422
|
else if (((_b = contract_metadata_1.default[checksumAddress]) === null || _b === void 0 ? void 0 : _b.erc20) === true) {
|
|
412
423
|
return Promise.resolve(false);
|
|
413
424
|
}
|
|
414
|
-
const tokenContract = this._createEthersContract(tokenAddress, metamask_eth_abis_1.abiERC721,
|
|
425
|
+
const tokenContract = this._createEthersContract(tokenAddress, metamask_eth_abis_1.abiERC721, networkClientId);
|
|
415
426
|
try {
|
|
416
427
|
return yield tokenContract.supportsInterface(controller_utils_1.ERC721_INTERFACE_ID);
|
|
417
428
|
}
|
|
@@ -424,8 +435,13 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
424
435
|
}
|
|
425
436
|
});
|
|
426
437
|
}
|
|
427
|
-
_createEthersContract(tokenAddress, abi,
|
|
428
|
-
|
|
438
|
+
_createEthersContract(tokenAddress, abi, networkClientId) {
|
|
439
|
+
var _a;
|
|
440
|
+
const provider = networkClientId
|
|
441
|
+
? this.getNetworkClientById(networkClientId).provider
|
|
442
|
+
: (_a = this.config) === null || _a === void 0 ? void 0 : _a.provider;
|
|
443
|
+
const web3provider = new providers_1.Web3Provider(provider);
|
|
444
|
+
const tokenContract = new contracts_1.Contract(tokenAddress, abi, web3provider);
|
|
429
445
|
return tokenContract;
|
|
430
446
|
}
|
|
431
447
|
_generateRandomId() {
|
|
@@ -435,12 +451,14 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
435
451
|
* Adds a new suggestedAsset to the list of watched assets.
|
|
436
452
|
* Parameters will be validated according to the asset type being watched.
|
|
437
453
|
*
|
|
438
|
-
* @param
|
|
439
|
-
* @param
|
|
440
|
-
* @param
|
|
454
|
+
* @param options - The method options.
|
|
455
|
+
* @param options.asset - The asset to be watched. For now only ERC20 tokens are accepted.
|
|
456
|
+
* @param options.type - The asset type.
|
|
457
|
+
* @param options.interactingAddress - The address of the account that is requesting to watch the asset.
|
|
458
|
+
* @param options.networkClientId - Network Client ID.
|
|
441
459
|
* @returns Object containing a Promise resolving to the suggestedAsset address if accepted.
|
|
442
460
|
*/
|
|
443
|
-
watchAsset(asset, type, interactingAddress) {
|
|
461
|
+
watchAsset({ asset, type, interactingAddress, networkClientId, }) {
|
|
444
462
|
return __awaiter(this, void 0, void 0, function* () {
|
|
445
463
|
if (type !== controller_utils_1.ERC20) {
|
|
446
464
|
throw new Error(`Asset of type ${type} not supported`);
|
|
@@ -457,15 +475,20 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
457
475
|
yield this._requestApproval(suggestedAssetMeta);
|
|
458
476
|
let name;
|
|
459
477
|
try {
|
|
460
|
-
name = yield this.getERC20TokenName(asset.address);
|
|
478
|
+
name = yield this.getERC20TokenName(asset.address, networkClientId);
|
|
461
479
|
}
|
|
462
480
|
catch (error) {
|
|
463
481
|
name = undefined;
|
|
464
482
|
}
|
|
465
|
-
|
|
483
|
+
const { address, symbol, decimals, image } = asset;
|
|
484
|
+
yield this.addToken({
|
|
485
|
+
address,
|
|
486
|
+
symbol,
|
|
487
|
+
decimals,
|
|
466
488
|
name,
|
|
467
|
-
image
|
|
489
|
+
image,
|
|
468
490
|
interactingAddress: suggestedAssetMeta.interactingAddress,
|
|
491
|
+
networkClientId,
|
|
469
492
|
});
|
|
470
493
|
});
|
|
471
494
|
}
|
|
@@ -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 { 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: AbortController;\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 AbortController();\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 AbortController();\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": "14.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",
|
|
@@ -33,18 +33,17 @@
|
|
|
33
33
|
"@ethersproject/contracts": "^5.7.0",
|
|
34
34
|
"@ethersproject/providers": "^5.7.0",
|
|
35
35
|
"@metamask/abi-utils": "^2.0.2",
|
|
36
|
-
"@metamask/approval-controller": "^3.5.
|
|
37
|
-
"@metamask/base-controller": "^3.2.
|
|
36
|
+
"@metamask/approval-controller": "^3.5.2",
|
|
37
|
+
"@metamask/base-controller": "^3.2.2",
|
|
38
38
|
"@metamask/contract-metadata": "^2.3.1",
|
|
39
|
-
"@metamask/controller-utils": "^
|
|
39
|
+
"@metamask/controller-utils": "^5.0.1",
|
|
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.
|
|
44
|
-
"@metamask/rpc-errors": "^
|
|
42
|
+
"@metamask/network-controller": "^13.0.1",
|
|
43
|
+
"@metamask/preferences-controller": "^4.4.2",
|
|
44
|
+
"@metamask/rpc-errors": "^6.0.0",
|
|
45
45
|
"@metamask/utils": "^6.2.0",
|
|
46
46
|
"@types/uuid": "^8.3.0",
|
|
47
|
-
"abort-controller": "^3.0.0",
|
|
48
47
|
"async-mutex": "^0.2.6",
|
|
49
48
|
"ethereumjs-util": "^7.0.10",
|
|
50
49
|
"immer": "^9.0.6",
|
|
@@ -63,14 +62,14 @@
|
|
|
63
62
|
"nock": "^13.3.1",
|
|
64
63
|
"sinon": "^9.2.4",
|
|
65
64
|
"ts-jest": "^27.1.4",
|
|
66
|
-
"typedoc": "^0.
|
|
67
|
-
"typedoc-plugin-missing-exports": "^0.
|
|
68
|
-
"typescript": "~4.
|
|
65
|
+
"typedoc": "^0.23.15",
|
|
66
|
+
"typedoc-plugin-missing-exports": "^0.23.0",
|
|
67
|
+
"typescript": "~4.8.4"
|
|
69
68
|
},
|
|
70
69
|
"peerDependencies": {
|
|
71
|
-
"@metamask/approval-controller": "^3.5.
|
|
72
|
-
"@metamask/network-controller": "^
|
|
73
|
-
"@metamask/preferences-controller": "^4.4.
|
|
70
|
+
"@metamask/approval-controller": "^3.5.2",
|
|
71
|
+
"@metamask/network-controller": "^13.0.1",
|
|
72
|
+
"@metamask/preferences-controller": "^4.4.2"
|
|
74
73
|
},
|
|
75
74
|
"engines": {
|
|
76
75
|
"node": ">=16.0.0"
|