@metamask-previews/assets-controllers 33.0.0-preview-83ca56e → 33.0.0-preview-30646c8e
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/dist/TokenBalancesController.js +2 -2
- package/dist/TokenBalancesController.mjs +1 -1
- package/dist/TokenDetectionController.js +2 -2
- package/dist/TokenDetectionController.mjs +1 -1
- package/dist/TokenRatesController.js +2 -2
- package/dist/TokenRatesController.mjs +1 -1
- package/dist/TokensController.js +2 -2
- package/dist/TokensController.mjs +1 -1
- package/dist/{chunk-2TSAUGE7.mjs → chunk-3K3LE2CZ.mjs} +19 -30
- package/dist/chunk-3K3LE2CZ.mjs.map +1 -0
- package/dist/{chunk-RPQ737HL.js → chunk-FGAZXVKS.js} +34 -36
- package/dist/chunk-FGAZXVKS.js.map +1 -0
- package/dist/{chunk-NHFZIY2K.js → chunk-NWVMFCSC.js} +4 -4
- package/dist/chunk-NWVMFCSC.js.map +1 -0
- package/dist/{chunk-6VQJFTNC.mjs → chunk-OEEFNXR7.mjs} +4 -4
- package/dist/chunk-OEEFNXR7.mjs.map +1 -0
- package/dist/{chunk-GJCTAKK5.mjs → chunk-P3O5CVAH.mjs} +34 -36
- package/dist/chunk-P3O5CVAH.mjs.map +1 -0
- package/dist/{chunk-2NQRWANM.js → chunk-RJBYLTY5.js} +30 -57
- package/dist/chunk-RJBYLTY5.js.map +1 -0
- package/dist/{chunk-4JLB5OIJ.mjs → chunk-UVE4XY5Y.mjs} +30 -57
- package/dist/chunk-UVE4XY5Y.mjs.map +1 -0
- package/dist/{chunk-GHKGU6GK.js → chunk-VZF43NDM.js} +19 -30
- package/dist/chunk-VZF43NDM.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/index.mjs +4 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/TokenBalancesController.d.ts +2 -2
- package/dist/types/TokenBalancesController.d.ts.map +1 -1
- package/dist/types/TokenDetectionController.d.ts +6 -4
- package/dist/types/TokenDetectionController.d.ts.map +1 -1
- package/dist/types/TokenRatesController.d.ts +3 -3
- package/dist/types/TokenRatesController.d.ts.map +1 -1
- package/dist/types/TokensController.d.ts +6 -4
- package/dist/types/TokensController.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2NQRWANM.js.map +0 -1
- package/dist/chunk-2TSAUGE7.mjs.map +0 -1
- package/dist/chunk-4JLB5OIJ.mjs.map +0 -1
- package/dist/chunk-6VQJFTNC.mjs.map +0 -1
- package/dist/chunk-GHKGU6GK.js.map +0 -1
- package/dist/chunk-GJCTAKK5.mjs.map +0 -1
- package/dist/chunk-NHFZIY2K.js.map +0 -1
- package/dist/chunk-RPQ737HL.js.map +0 -1
|
@@ -76,18 +76,20 @@ var getDefaultTokensState = () => {
|
|
|
76
76
|
allDetectedTokens: {}
|
|
77
77
|
};
|
|
78
78
|
};
|
|
79
|
-
var _mutex, _chainId,
|
|
79
|
+
var _mutex, _chainId, _selectedAddress, _provider, _abortController, _onNetworkDidChange, onNetworkDidChange_fn, _onPreferenceControllerStateChange, onPreferenceControllerStateChange_fn, _fetchTokenMetadata, fetchTokenMetadata_fn, _updateTokensAttribute, updateTokensAttribute_fn, _detectIsERC721, detectIsERC721_fn, _getProvider, getProvider_fn, _createEthersContract, createEthersContract_fn, _generateRandomId, generateRandomId_fn, _getNewAllTokensState, getNewAllTokensState_fn, _requestApproval, requestApproval_fn;
|
|
80
80
|
var TokensController = class extends BaseController {
|
|
81
81
|
/**
|
|
82
82
|
* Tokens controller options
|
|
83
83
|
* @param options - Constructor options.
|
|
84
84
|
* @param options.chainId - The chain ID of the current network.
|
|
85
|
+
* @param options.selectedAddress - Vault selected address
|
|
85
86
|
* @param options.provider - Network provider.
|
|
86
87
|
* @param options.state - Initial state to set on this controller.
|
|
87
88
|
* @param options.messenger - The controller messenger.
|
|
88
89
|
*/
|
|
89
90
|
constructor({
|
|
90
91
|
chainId: initialChainId,
|
|
92
|
+
selectedAddress,
|
|
91
93
|
provider,
|
|
92
94
|
state,
|
|
93
95
|
messenger
|
|
@@ -110,10 +112,11 @@ var TokensController = class extends BaseController {
|
|
|
110
112
|
*/
|
|
111
113
|
__privateAdd(this, _onNetworkDidChange);
|
|
112
114
|
/**
|
|
113
|
-
* Handles the
|
|
114
|
-
* @param
|
|
115
|
+
* Handles the state change of the preference controller.
|
|
116
|
+
* @param preferencesState - The new state of the preference controller.
|
|
117
|
+
* @param preferencesState.selectedAddress - The current selected address of the preference controller.
|
|
115
118
|
*/
|
|
116
|
-
__privateAdd(this,
|
|
119
|
+
__privateAdd(this, _onPreferenceControllerStateChange);
|
|
117
120
|
/**
|
|
118
121
|
* Fetch metadata for a token.
|
|
119
122
|
*
|
|
@@ -153,27 +156,23 @@ var TokensController = class extends BaseController {
|
|
|
153
156
|
* @returns The updated `allTokens` and `allIgnoredTokens` state.
|
|
154
157
|
*/
|
|
155
158
|
__privateAdd(this, _getNewAllTokensState);
|
|
156
|
-
__privateAdd(this, _getAddressOrSelectedAddress);
|
|
157
|
-
__privateAdd(this, _isInteractingWithWallet);
|
|
158
159
|
__privateAdd(this, _requestApproval);
|
|
159
|
-
__privateAdd(this, _getSelectedAccount);
|
|
160
|
-
__privateAdd(this, _getSelectedAddress);
|
|
161
160
|
__privateAdd(this, _mutex, new Mutex());
|
|
162
161
|
__privateAdd(this, _chainId, void 0);
|
|
163
|
-
__privateAdd(this,
|
|
162
|
+
__privateAdd(this, _selectedAddress, void 0);
|
|
164
163
|
__privateAdd(this, _provider, void 0);
|
|
165
164
|
__privateAdd(this, _abortController, void 0);
|
|
166
165
|
__privateSet(this, _chainId, initialChainId);
|
|
167
166
|
__privateSet(this, _provider, provider);
|
|
168
|
-
__privateSet(this,
|
|
167
|
+
__privateSet(this, _selectedAddress, selectedAddress);
|
|
169
168
|
__privateSet(this, _abortController, new AbortController());
|
|
170
169
|
this.messagingSystem.registerActionHandler(
|
|
171
170
|
`${controllerName}:addDetectedTokens`,
|
|
172
171
|
this.addDetectedTokens.bind(this)
|
|
173
172
|
);
|
|
174
173
|
this.messagingSystem.subscribe(
|
|
175
|
-
"
|
|
176
|
-
__privateMethod(this,
|
|
174
|
+
"PreferencesController:stateChange",
|
|
175
|
+
__privateMethod(this, _onPreferenceControllerStateChange, onPreferenceControllerStateChange_fn).bind(this)
|
|
177
176
|
);
|
|
178
177
|
this.messagingSystem.subscribe(
|
|
179
178
|
"NetworkController:networkDidChange",
|
|
@@ -212,6 +211,7 @@ var TokensController = class extends BaseController {
|
|
|
212
211
|
networkClientId
|
|
213
212
|
}) {
|
|
214
213
|
const chainId = __privateGet(this, _chainId);
|
|
214
|
+
const selectedAddress = __privateGet(this, _selectedAddress);
|
|
215
215
|
const releaseLock = await __privateGet(this, _mutex).acquire();
|
|
216
216
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
217
217
|
let currentChainId = chainId;
|
|
@@ -221,8 +221,8 @@ var TokensController = class extends BaseController {
|
|
|
221
221
|
networkClientId
|
|
222
222
|
).configuration.chainId;
|
|
223
223
|
}
|
|
224
|
-
const accountAddress =
|
|
225
|
-
const isInteractingWithWalletAccount =
|
|
224
|
+
const accountAddress = interactingAddress || selectedAddress;
|
|
225
|
+
const isInteractingWithWalletAccount = accountAddress === selectedAddress;
|
|
226
226
|
try {
|
|
227
227
|
address = toChecksumHexAddress(address);
|
|
228
228
|
const tokens = allTokens[currentChainId]?.[accountAddress] || [];
|
|
@@ -401,7 +401,7 @@ var TokensController = class extends BaseController {
|
|
|
401
401
|
async addDetectedTokens(incomingDetectedTokens, detectionDetails) {
|
|
402
402
|
const releaseLock = await __privateGet(this, _mutex).acquire();
|
|
403
403
|
const chainId = detectionDetails?.chainId ?? __privateGet(this, _chainId);
|
|
404
|
-
const accountAddress = detectionDetails?.selectedAddress ??
|
|
404
|
+
const accountAddress = detectionDetails?.selectedAddress ?? __privateGet(this, _selectedAddress);
|
|
405
405
|
const { allTokens, allDetectedTokens, allIgnoredTokens } = this.state;
|
|
406
406
|
let newTokens = [...allTokens?.[chainId]?.[accountAddress] ?? []];
|
|
407
407
|
let newDetectedTokens = [
|
|
@@ -453,9 +453,8 @@ var TokensController = class extends BaseController {
|
|
|
453
453
|
interactingAddress: accountAddress,
|
|
454
454
|
interactingChainId: chainId
|
|
455
455
|
});
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
newDetectedTokens = newAllDetectedTokens?.[__privateGet(this, _chainId)]?.[selectedAddress] || [];
|
|
456
|
+
newTokens = newAllTokens?.[__privateGet(this, _chainId)]?.[__privateGet(this, _selectedAddress)] || [];
|
|
457
|
+
newDetectedTokens = newAllDetectedTokens?.[__privateGet(this, _chainId)]?.[__privateGet(this, _selectedAddress)] || [];
|
|
459
458
|
this.update((state) => {
|
|
460
459
|
state.tokens = newTokens;
|
|
461
460
|
state.allTokens = newAllTokens;
|
|
@@ -512,7 +511,6 @@ var TokensController = class extends BaseController {
|
|
|
512
511
|
if (!isValidHexAddress(asset.address)) {
|
|
513
512
|
throw rpcErrors.invalidParams(`Invalid address "${asset.address}"`);
|
|
514
513
|
}
|
|
515
|
-
const selectedAddress = __privateMethod(this, _getAddressOrSelectedAddress, getAddressOrSelectedAddress_fn).call(this, interactingAddress);
|
|
516
514
|
if (await __privateMethod(this, _detectIsERC721, detectIsERC721_fn).call(this, asset.address, networkClientId)) {
|
|
517
515
|
throw rpcErrors.invalidParams(
|
|
518
516
|
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
@@ -588,7 +586,7 @@ var TokensController = class extends BaseController {
|
|
|
588
586
|
id: __privateMethod(this, _generateRandomId, generateRandomId_fn).call(this),
|
|
589
587
|
time: Date.now(),
|
|
590
588
|
type,
|
|
591
|
-
interactingAddress:
|
|
589
|
+
interactingAddress: interactingAddress || __privateGet(this, _selectedAddress)
|
|
592
590
|
};
|
|
593
591
|
await __privateMethod(this, _requestApproval, requestApproval_fn).call(this, suggestedAssetMeta);
|
|
594
592
|
const { address, symbol, decimals, name, image } = asset;
|
|
@@ -614,7 +612,7 @@ var TokensController = class extends BaseController {
|
|
|
614
612
|
};
|
|
615
613
|
_mutex = new WeakMap();
|
|
616
614
|
_chainId = new WeakMap();
|
|
617
|
-
|
|
615
|
+
_selectedAddress = new WeakMap();
|
|
618
616
|
_provider = new WeakMap();
|
|
619
617
|
_abortController = new WeakMap();
|
|
620
618
|
_onNetworkDidChange = new WeakSet();
|
|
@@ -628,21 +626,20 @@ onNetworkDidChange_fn = function({ selectedNetworkClientId }) {
|
|
|
628
626
|
__privateGet(this, _abortController).abort();
|
|
629
627
|
__privateSet(this, _abortController, new AbortController());
|
|
630
628
|
__privateSet(this, _chainId, chainId);
|
|
631
|
-
const selectedAddress = __privateMethod(this, _getSelectedAddress, getSelectedAddress_fn).call(this);
|
|
632
629
|
this.update((state) => {
|
|
633
|
-
state.tokens = allTokens[chainId]?.[
|
|
634
|
-
state.ignoredTokens = allIgnoredTokens[chainId]?.[
|
|
635
|
-
state.detectedTokens = allDetectedTokens[chainId]?.[
|
|
630
|
+
state.tokens = allTokens[chainId]?.[__privateGet(this, _selectedAddress)] || [];
|
|
631
|
+
state.ignoredTokens = allIgnoredTokens[chainId]?.[__privateGet(this, _selectedAddress)] || [];
|
|
632
|
+
state.detectedTokens = allDetectedTokens[chainId]?.[__privateGet(this, _selectedAddress)] || [];
|
|
636
633
|
});
|
|
637
634
|
};
|
|
638
|
-
|
|
639
|
-
|
|
635
|
+
_onPreferenceControllerStateChange = new WeakSet();
|
|
636
|
+
onPreferenceControllerStateChange_fn = function({ selectedAddress }) {
|
|
640
637
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
641
|
-
__privateSet(this,
|
|
638
|
+
__privateSet(this, _selectedAddress, selectedAddress);
|
|
642
639
|
this.update((state) => {
|
|
643
|
-
state.tokens = allTokens[__privateGet(this, _chainId)]?.[
|
|
644
|
-
state.ignoredTokens = allIgnoredTokens[__privateGet(this, _chainId)]?.[
|
|
645
|
-
state.detectedTokens = allDetectedTokens[__privateGet(this, _chainId)]?.[
|
|
640
|
+
state.tokens = allTokens[__privateGet(this, _chainId)]?.[selectedAddress] ?? [];
|
|
641
|
+
state.ignoredTokens = allIgnoredTokens[__privateGet(this, _chainId)]?.[selectedAddress] ?? [];
|
|
642
|
+
state.detectedTokens = allDetectedTokens[__privateGet(this, _chainId)]?.[selectedAddress] ?? [];
|
|
646
643
|
});
|
|
647
644
|
};
|
|
648
645
|
_fetchTokenMetadata = new WeakSet();
|
|
@@ -717,7 +714,7 @@ getNewAllTokensState_fn = function(params) {
|
|
|
717
714
|
interactingChainId
|
|
718
715
|
} = params;
|
|
719
716
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
720
|
-
const userAddressToAddTokens =
|
|
717
|
+
const userAddressToAddTokens = interactingAddress ?? __privateGet(this, _selectedAddress);
|
|
721
718
|
const chainIdToAddTokens = interactingChainId ?? __privateGet(this, _chainId);
|
|
722
719
|
let newAllTokens = allTokens;
|
|
723
720
|
if (newTokens?.length || newTokens && allTokens && allTokens[chainIdToAddTokens] && allTokens[chainIdToAddTokens][userAddressToAddTokens]) {
|
|
@@ -757,18 +754,6 @@ getNewAllTokensState_fn = function(params) {
|
|
|
757
754
|
}
|
|
758
755
|
return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };
|
|
759
756
|
};
|
|
760
|
-
_getAddressOrSelectedAddress = new WeakSet();
|
|
761
|
-
getAddressOrSelectedAddress_fn = function(address) {
|
|
762
|
-
if (address) {
|
|
763
|
-
return address;
|
|
764
|
-
}
|
|
765
|
-
return __privateMethod(this, _getSelectedAddress, getSelectedAddress_fn).call(this);
|
|
766
|
-
};
|
|
767
|
-
_isInteractingWithWallet = new WeakSet();
|
|
768
|
-
isInteractingWithWallet_fn = function(address) {
|
|
769
|
-
const selectedAddress = __privateMethod(this, _getSelectedAddress, getSelectedAddress_fn).call(this);
|
|
770
|
-
return selectedAddress === address;
|
|
771
|
-
};
|
|
772
757
|
_requestApproval = new WeakSet();
|
|
773
758
|
requestApproval_fn = async function(suggestedAssetMeta) {
|
|
774
759
|
return this.messagingSystem.call(
|
|
@@ -791,18 +776,6 @@ requestApproval_fn = async function(suggestedAssetMeta) {
|
|
|
791
776
|
true
|
|
792
777
|
);
|
|
793
778
|
};
|
|
794
|
-
_getSelectedAccount = new WeakSet();
|
|
795
|
-
getSelectedAccount_fn = function() {
|
|
796
|
-
return this.messagingSystem.call("AccountsController:getSelectedAccount");
|
|
797
|
-
};
|
|
798
|
-
_getSelectedAddress = new WeakSet();
|
|
799
|
-
getSelectedAddress_fn = function() {
|
|
800
|
-
const account = this.messagingSystem.call(
|
|
801
|
-
"AccountsController:getAccount",
|
|
802
|
-
__privateGet(this, _selectedAccountId)
|
|
803
|
-
);
|
|
804
|
-
return account?.address || "";
|
|
805
|
-
};
|
|
806
779
|
var TokensController_default = TokensController;
|
|
807
780
|
|
|
808
781
|
export {
|
|
@@ -810,4 +783,4 @@ export {
|
|
|
810
783
|
TokensController,
|
|
811
784
|
TokensController_default
|
|
812
785
|
};
|
|
813
|
-
//# sourceMappingURL=chunk-
|
|
786
|
+
//# sourceMappingURL=chunk-UVE4XY5Y.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/TokensController.ts"],"sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { AddApprovalRequest } from '@metamask/approval-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\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 ERC721,\n ERC1155,\n isValidHexAddress,\n safelyExecute,\n} from '@metamask/controller-utils';\nimport { abiERC721 } from '@metamask/metamask-eth-abis';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerNetworkDidChangeEvent,\n NetworkState,\n Provider,\n} from '@metamask/network-controller';\nimport type {\n PreferencesControllerStateChangeEvent,\n PreferencesState,\n} from '@metamask/preferences-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { v1 as random } from 'uuid';\n\nimport { formatAggregatorNames, formatIconUrlWithProxy } from './assetsUtil';\nimport { ERC20Standard } from './Standards/ERC20Standard';\nimport { ERC1155Standard } from './Standards/NftStandards/ERC1155/ERC1155Standard';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from './token-service';\nimport type {\n TokenListMap,\n TokenListStateChange,\n TokenListToken,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\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 TokensControllerState\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 type TokensControllerState = {\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\nconst metadata = {\n tokens: {\n persist: true,\n anonymous: false,\n },\n ignoredTokens: {\n persist: true,\n anonymous: false,\n },\n detectedTokens: {\n persist: true,\n anonymous: false,\n },\n allTokens: {\n persist: true,\n anonymous: false,\n },\n allIgnoredTokens: {\n persist: true,\n anonymous: false,\n },\n allDetectedTokens: {\n persist: true,\n anonymous: false,\n },\n};\n\nconst controllerName = 'TokensController';\n\nexport type TokensControllerActions =\n | TokensControllerGetStateAction\n | TokensControllerAddDetectedTokensAction;\n\nexport type TokensControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokensControllerState\n>;\n\nexport type TokensControllerAddDetectedTokensAction = {\n type: `${typeof controllerName}:addDetectedTokens`;\n handler: TokensController['addDetectedTokens'];\n};\n\n/**\n * The external actions available to the {@link TokensController}.\n */\nexport type AllowedActions =\n | AddApprovalRequest\n | NetworkControllerGetNetworkClientByIdAction;\n\nexport type TokensControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n TokensControllerState\n>;\n\nexport type TokensControllerEvents = TokensControllerStateChangeEvent;\n\nexport type AllowedEvents =\n | NetworkControllerNetworkDidChangeEvent\n | PreferencesControllerStateChangeEvent\n | TokenListStateChange;\n\n/**\n * The messenger of the {@link TokensController}.\n */\nexport type TokensControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokensControllerActions | AllowedActions,\n TokensControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\nexport const getDefaultTokensState = (): TokensControllerState => {\n return {\n tokens: [],\n ignoredTokens: [],\n detectedTokens: [],\n allTokens: {},\n allIgnoredTokens: {},\n allDetectedTokens: {},\n };\n};\n\n/**\n * Controller that stores assets and exposes convenience methods\n */\nexport class TokensController extends BaseController<\n typeof controllerName,\n TokensControllerState,\n TokensControllerMessenger\n> {\n readonly #mutex = new Mutex();\n\n #chainId: Hex;\n\n #selectedAddress: string;\n\n #provider: Provider | undefined;\n\n #abortController: AbortController;\n\n /**\n * Tokens controller options\n * @param options - Constructor options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.selectedAddress - Vault selected address\n * @param options.provider - Network provider.\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 selectedAddress,\n provider,\n state,\n messenger,\n }: {\n chainId: Hex;\n selectedAddress: string;\n provider: Provider | undefined;\n state?: Partial<TokensControllerState>;\n messenger: TokensControllerMessenger;\n }) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultTokensState(),\n ...state,\n },\n });\n\n this.#chainId = initialChainId;\n\n this.#provider = provider;\n\n this.#selectedAddress = selectedAddress;\n\n this.#abortController = new AbortController();\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:addDetectedTokens` as const,\n this.addDetectedTokens.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'PreferencesController:stateChange',\n this.#onPreferenceControllerStateChange.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'NetworkController:networkDidChange',\n this.#onNetworkDidChange.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'TokenListController:stateChange',\n ({ tokenList }) => {\n const { tokens } = this.state;\n if (tokens.length && !tokens[0].name) {\n this.#updateTokensAttribute(tokenList, 'name');\n }\n },\n );\n }\n\n /**\n * Handles the event when the network changes.\n *\n * @param networkState - The changed network state.\n * @param networkState.selectedNetworkClientId - The ID of the currently\n * selected network client.\n */\n #onNetworkDidChange({ selectedNetworkClientId }: NetworkState) {\n const selectedNetworkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = selectedNetworkClient.configuration;\n this.#abortController.abort();\n this.#abortController = new AbortController();\n this.#chainId = chainId;\n this.update((state) => {\n state.tokens = allTokens[chainId]?.[this.#selectedAddress] || [];\n state.ignoredTokens =\n allIgnoredTokens[chainId]?.[this.#selectedAddress] || [];\n state.detectedTokens =\n allDetectedTokens[chainId]?.[this.#selectedAddress] || [];\n });\n }\n\n /**\n * Handles the state change of the preference controller.\n * @param preferencesState - The new state of the preference controller.\n * @param preferencesState.selectedAddress - The current selected address of the preference controller.\n */\n #onPreferenceControllerStateChange({ selectedAddress }: PreferencesState) {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n this.#selectedAddress = selectedAddress;\n this.update((state) => {\n state.tokens = allTokens[this.#chainId]?.[selectedAddress] ?? [];\n state.ignoredTokens =\n allIgnoredTokens[this.#chainId]?.[selectedAddress] ?? [];\n state.detectedTokens =\n allDetectedTokens[this.#chainId]?.[selectedAddress] ?? [];\n });\n }\n\n /**\n * Fetch metadata for a token.\n *\n * @param tokenAddress - The address of the token.\n * @returns The token metadata.\n */\n async #fetchTokenMetadata(\n tokenAddress: string,\n ): Promise<TokenListToken | undefined> {\n try {\n const token = await fetchTokenMetadata<TokenListToken>(\n this.#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 * 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 chainId = this.#chainId;\n const selectedAddress = this.#selectedAddress;\n const releaseLock = await this.#mutex.acquire();\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n let currentChainId = chainId;\n if (networkClientId) {\n currentChainId = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n ).configuration.chainId;\n }\n\n const accountAddress = interactingAddress || selectedAddress;\n const isInteractingWithWalletAccount = accountAddress === selectedAddress;\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 // TODO parameterize the token metadata fetch by networkClientId\n this.#fetchTokenMetadata(address),\n ]);\n // TODO remove this once this method is fully parameterized by networkClientId\n if (!networkClientId && currentChainId !== this.#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 previousIndex = newTokens.findIndex(\n (token) => token.address.toLowerCase() === address.toLowerCase(),\n );\n if (previousIndex !== -1) {\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<TokensControllerState> = {\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((state) => {\n Object.assign(state, newState);\n });\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 = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n ).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((state) => {\n state.tokens = newTokens;\n state.allTokens = newAllTokens;\n state.detectedTokens = newDetectedTokens;\n state.allDetectedTokens = newAllDetectedTokens;\n state.ignoredTokens = newIgnoredTokens;\n state.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((state) => {\n state.ignoredTokens = newIgnoredTokens;\n state.tokens = newTokens;\n state.detectedTokens = newDetectedTokens;\n state.allIgnoredTokens = newAllIgnoredTokens;\n state.allDetectedTokens = newAllDetectedTokens;\n state.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\n // Get existing tokens for the chain + account\n const chainId = detectionDetails?.chainId ?? this.#chainId;\n const accountAddress =\n detectionDetails?.selectedAddress ?? this.#selectedAddress;\n\n const { allTokens, allDetectedTokens, allIgnoredTokens } = this.state;\n let newTokens = [...(allTokens?.[chainId]?.[accountAddress] ?? [])];\n let newDetectedTokens = [\n ...(allDetectedTokens?.[chainId]?.[accountAddress] ?? []),\n ];\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 previousImportedIndex = newTokens.findIndex(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousImportedIndex !== -1) {\n // Update existing data of imported token\n newTokens[previousImportedIndex] = newEntry;\n } else {\n const ignoredTokenIndex =\n allIgnoredTokens?.[chainId]?.[accountAddress]?.indexOf(address) ??\n -1;\n\n if (ignoredTokenIndex === -1) {\n // Add detected token\n const previousDetectedIndex = newDetectedTokens.findIndex(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousDetectedIndex !== -1) {\n newDetectedTokens[previousDetectedIndex] = newEntry;\n } else {\n newDetectedTokens.push(newEntry);\n }\n }\n }\n });\n\n const { newAllTokens, newAllDetectedTokens } = this.#getNewAllTokensState(\n {\n newTokens,\n newDetectedTokens,\n interactingAddress: accountAddress,\n interactingChainId: chainId,\n },\n );\n\n // We may be detecting tokens on a different chain/account pair than are currently configured.\n // Re-point `tokens` and `detectedTokens` to keep them referencing the current chain/account.\n newTokens = newAllTokens?.[this.#chainId]?.[this.#selectedAddress] || [];\n newDetectedTokens =\n newAllDetectedTokens?.[this.#chainId]?.[this.#selectedAddress] || [];\n\n this.update((state) => {\n state.tokens = newTokens;\n state.allTokens = newAllTokens;\n state.detectedTokens = newDetectedTokens;\n state.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.tokens];\n const tokenIndex = tokens.findIndex((token) => {\n return token.address.toLowerCase() === tokenAddress.toLowerCase();\n });\n const updatedToken = { ...tokens[tokenIndex], isERC721 };\n tokens[tokenIndex] = updatedToken;\n this.update((state) => {\n state.tokens = tokens;\n });\n return updatedToken;\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 #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((state) => {\n state.tokens = newTokens;\n });\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) {\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 #getProvider(networkClientId?: NetworkClientId): Web3Provider {\n return new Web3Provider(\n // @ts-expect-error TODO: remove this annotation once the `Eip1193Provider` class is released\n networkClientId\n ? this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n ).provider\n : this.#provider,\n );\n }\n\n #createEthersContract(\n tokenAddress: string,\n abi: string,\n networkClientId?: NetworkClientId,\n ): Contract {\n const web3provider = this.#getProvider(networkClientId);\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 A promise that resolves if the asset was watched successfully, and rejects otherwise.\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 if (!asset.address) {\n throw rpcErrors.invalidParams('Address must be specified');\n }\n\n if (!isValidHexAddress(asset.address)) {\n throw rpcErrors.invalidParams(`Invalid address \"${asset.address}\"`);\n }\n\n // Validate contract\n\n if (await this.#detectIsERC721(asset.address, networkClientId)) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Contract ${asset.address} must match type ${type}, but was detected as ${ERC721}`,\n );\n }\n\n const provider = this.#getProvider(networkClientId);\n const isErc1155 = await safelyExecute(() =>\n new ERC1155Standard(provider).contractSupportsBase1155Interface(\n asset.address,\n ),\n );\n if (isErc1155) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Contract ${asset.address} must match type ${type}, but was detected as ${ERC1155}`,\n );\n }\n\n const erc20 = new ERC20Standard(provider);\n const [contractName, contractSymbol, contractDecimals] = await Promise.all([\n safelyExecute(() => erc20.getTokenName(asset.address)),\n safelyExecute(() => erc20.getTokenSymbol(asset.address)),\n safelyExecute(async () => erc20.getTokenDecimals(asset.address)),\n ]);\n\n asset.name = contractName;\n\n // Validate symbol\n\n if (!asset.symbol && !contractSymbol) {\n throw rpcErrors.invalidParams(\n 'A symbol is required, but was not found in either the request or contract',\n );\n }\n\n if (\n contractSymbol !== undefined &&\n asset.symbol !== undefined &&\n asset.symbol.toUpperCase() !== contractSymbol.toUpperCase()\n ) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `The symbol in the request (${asset.symbol}) does not match the symbol in the contract (${contractSymbol})`,\n );\n }\n\n asset.symbol = contractSymbol ?? asset.symbol;\n if (typeof asset.symbol !== 'string') {\n throw rpcErrors.invalidParams(`Invalid symbol: not a string`);\n }\n\n if (asset.symbol.length > 11) {\n throw rpcErrors.invalidParams(\n `Invalid symbol \"${asset.symbol}\": longer than 11 characters`,\n );\n }\n\n // Validate decimals\n\n if (asset.decimals === undefined && contractDecimals === undefined) {\n throw rpcErrors.invalidParams(\n 'Decimals are required, but were not found in either the request or contract',\n );\n }\n\n if (\n contractDecimals !== undefined &&\n asset.decimals !== undefined &&\n String(asset.decimals) !== contractDecimals\n ) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `The decimals in the request (${asset.decimals}) do not match the decimals in the contract (${contractDecimals})`,\n );\n }\n\n const decimalsStr = contractDecimals ?? asset.decimals;\n const decimalsNum = parseInt(decimalsStr as unknown as string, 10);\n if (!Number.isInteger(decimalsNum) || decimalsNum > 36 || decimalsNum < 0) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Invalid decimals \"${decimalsStr}\": must be an integer 0 <= 36`,\n );\n }\n asset.decimals = decimalsNum;\n\n const suggestedAssetMeta: SuggestedAssetMeta = {\n asset,\n id: this.#generateRandomId(),\n time: Date.now(),\n type,\n interactingAddress: interactingAddress || this.#selectedAddress,\n };\n\n await this.#requestApproval(suggestedAssetMeta);\n\n const { address, symbol, decimals, name, 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\n const userAddressToAddTokens = interactingAddress ?? this.#selectedAddress;\n const chainIdToAddTokens = interactingChainId ?? this.#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((state) => {\n state.ignoredTokens = [];\n state.allIgnoredTokens = {};\n });\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"],"mappings":"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","names":[]}
|
|
@@ -34,7 +34,7 @@ var STATIC_MAINNET_TOKEN_LIST = Object.entries(
|
|
|
34
34
|
};
|
|
35
35
|
}, {});
|
|
36
36
|
var controllerName = "TokenDetectionController";
|
|
37
|
-
var _intervalId,
|
|
37
|
+
var _intervalId, _selectedAddress, _networkClientId, _tokenList, _disabled, _isUnlocked, _isDetectionEnabledFromPreferences, _isDetectionEnabledForNetwork, _getBalancesInSingleCall, _trackMetaMetricsEvent, _registerEventListeners, registerEventListeners_fn, _stopPolling, stopPolling_fn, _startPolling, startPolling_fn, _getCorrectChainIdAndNetworkClientId, getCorrectChainIdAndNetworkClientId_fn, _restartTokenDetection, restartTokenDetection_fn, _getSlicesOfTokensToDetect, getSlicesOfTokensToDetect_fn, _addDetectedTokens, addDetectedTokens_fn;
|
|
38
38
|
var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPollingController {
|
|
39
39
|
/**
|
|
40
40
|
* Creates a TokenDetectionController instance.
|
|
@@ -43,10 +43,12 @@ var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPo
|
|
|
43
43
|
* @param options.messenger - The controller messaging system.
|
|
44
44
|
* @param options.disabled - If set to true, all network requests are blocked.
|
|
45
45
|
* @param options.interval - Polling interval used to fetch new token rates
|
|
46
|
+
* @param options.selectedAddress - Vault selected address
|
|
46
47
|
* @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.
|
|
47
48
|
* @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.
|
|
48
49
|
*/
|
|
49
50
|
constructor({
|
|
51
|
+
selectedAddress,
|
|
50
52
|
interval = DEFAULT_INTERVAL,
|
|
51
53
|
disabled = true,
|
|
52
54
|
getBalancesInSingleCall,
|
|
@@ -80,10 +82,8 @@ var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPo
|
|
|
80
82
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _restartTokenDetection);
|
|
81
83
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _getSlicesOfTokensToDetect);
|
|
82
84
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _addDetectedTokens);
|
|
83
|
-
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _getSelectedAccount);
|
|
84
|
-
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _getSelectedAddress);
|
|
85
85
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _intervalId, void 0);
|
|
86
|
-
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this,
|
|
86
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _selectedAddress, void 0);
|
|
87
87
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _networkClientId, void 0);
|
|
88
88
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _tokenList, {});
|
|
89
89
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _disabled, void 0);
|
|
@@ -94,7 +94,7 @@ var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPo
|
|
|
94
94
|
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _trackMetaMetricsEvent, void 0);
|
|
95
95
|
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _disabled, disabled);
|
|
96
96
|
this.setIntervalLength(interval);
|
|
97
|
-
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this,
|
|
97
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _selectedAddress, selectedAddress ?? this.messagingSystem.call("AccountsController:getSelectedAccount").address);
|
|
98
98
|
const { chainId, networkClientId } = _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getCorrectChainIdAndNetworkClientId, getCorrectChainIdAndNetworkClientId_fn).call(this);
|
|
99
99
|
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _networkClientId, networkClientId);
|
|
100
100
|
const { useTokenDetection: defaultUseTokenDetection } = this.messagingSystem.call("PreferencesController:getState");
|
|
@@ -165,7 +165,7 @@ var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPo
|
|
|
165
165
|
if (!this.isActive) {
|
|
166
166
|
return;
|
|
167
167
|
}
|
|
168
|
-
const addressAgainstWhichToDetect = selectedAddress ?? _chunkZ4BLTVTBjs.
|
|
168
|
+
const addressAgainstWhichToDetect = selectedAddress ?? _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress);
|
|
169
169
|
const { chainId, networkClientId: selectedNetworkClientId } = _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getCorrectChainIdAndNetworkClientId, getCorrectChainIdAndNetworkClientId_fn).call(this, networkClientId);
|
|
170
170
|
const chainIdAgainstWhichToDetect = chainId;
|
|
171
171
|
const networkClientIdAgainstWhichToDetect = selectedNetworkClientId;
|
|
@@ -194,7 +194,7 @@ var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPo
|
|
|
194
194
|
}
|
|
195
195
|
};
|
|
196
196
|
_intervalId = new WeakMap();
|
|
197
|
-
|
|
197
|
+
_selectedAddress = new WeakMap();
|
|
198
198
|
_networkClientId = new WeakMap();
|
|
199
199
|
_tokenList = new WeakMap();
|
|
200
200
|
_disabled = new WeakMap();
|
|
@@ -228,27 +228,28 @@ registerEventListeners_fn = function() {
|
|
|
228
228
|
"PreferencesController:stateChange",
|
|
229
229
|
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
230
230
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
231
|
-
async ({ useTokenDetection }) => {
|
|
232
|
-
const
|
|
231
|
+
async ({ selectedAddress: newSelectedAddress, useTokenDetection }) => {
|
|
232
|
+
const isSelectedAddressChanged = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress) !== newSelectedAddress;
|
|
233
233
|
const isDetectionChangedFromPreferences = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _isDetectionEnabledFromPreferences) !== useTokenDetection;
|
|
234
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _selectedAddress, newSelectedAddress);
|
|
234
235
|
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _isDetectionEnabledFromPreferences, useTokenDetection);
|
|
235
|
-
if (isDetectionChangedFromPreferences) {
|
|
236
|
+
if (isSelectedAddressChanged || isDetectionChangedFromPreferences) {
|
|
236
237
|
await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _restartTokenDetection, restartTokenDetection_fn).call(this, {
|
|
237
|
-
selectedAddress:
|
|
238
|
+
selectedAddress: _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress)
|
|
238
239
|
});
|
|
239
240
|
}
|
|
240
241
|
}
|
|
241
242
|
);
|
|
242
243
|
this.messagingSystem.subscribe(
|
|
243
|
-
"AccountsController:
|
|
244
|
+
"AccountsController:selectedAccountChange",
|
|
244
245
|
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
245
246
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
246
|
-
async (
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
249
|
-
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this,
|
|
247
|
+
async ({ address: newSelectedAddress }) => {
|
|
248
|
+
const isSelectedAddressChanged = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress) !== newSelectedAddress;
|
|
249
|
+
if (isSelectedAddressChanged) {
|
|
250
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _selectedAddress, newSelectedAddress);
|
|
250
251
|
await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _restartTokenDetection, restartTokenDetection_fn).call(this, {
|
|
251
|
-
selectedAddress:
|
|
252
|
+
selectedAddress: _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress)
|
|
252
253
|
});
|
|
253
254
|
}
|
|
254
255
|
}
|
|
@@ -410,18 +411,6 @@ addDetectedTokens_fn = async function({
|
|
|
410
411
|
}
|
|
411
412
|
});
|
|
412
413
|
};
|
|
413
|
-
_getSelectedAccount = new WeakSet();
|
|
414
|
-
getSelectedAccount_fn = function() {
|
|
415
|
-
return this.messagingSystem.call("AccountsController:getSelectedAccount");
|
|
416
|
-
};
|
|
417
|
-
_getSelectedAddress = new WeakSet();
|
|
418
|
-
getSelectedAddress_fn = function() {
|
|
419
|
-
const account = this.messagingSystem.call(
|
|
420
|
-
"AccountsController:getAccount",
|
|
421
|
-
_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAccountId)
|
|
422
|
-
);
|
|
423
|
-
return account?.address || "";
|
|
424
|
-
};
|
|
425
414
|
var TokenDetectionController_default = TokenDetectionController;
|
|
426
415
|
|
|
427
416
|
|
|
@@ -431,4 +420,4 @@ var TokenDetectionController_default = TokenDetectionController;
|
|
|
431
420
|
|
|
432
421
|
|
|
433
422
|
exports.isEqualCaseInsensitive = isEqualCaseInsensitive; exports.STATIC_MAINNET_TOKEN_LIST = STATIC_MAINNET_TOKEN_LIST; exports.controllerName = controllerName; exports.TokenDetectionController = TokenDetectionController; exports.TokenDetectionController_default = TokenDetectionController_default;
|
|
434
|
-
//# sourceMappingURL=chunk-
|
|
423
|
+
//# sourceMappingURL=chunk-VZF43NDM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/TokenDetectionController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport contractMap from '@metamask/contract-metadata';\nimport { ChainId, safelyExecute } from '@metamask/controller-utils';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetNetworkConfigurationByNetworkClientId,\n NetworkControllerGetStateAction,\n NetworkControllerNetworkDidChangeEvent,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n PreferencesControllerGetStateAction,\n PreferencesControllerStateChangeEvent,\n} from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport { isTokenDetectionSupportedForNetwork } from './assetsUtil';\nimport type {\n GetTokenListState,\n TokenListMap,\n TokenListStateChange,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\nimport type {\n TokensControllerAddDetectedTokensAction,\n TokensControllerGetStateAction,\n} from './TokensController';\n\nconst DEFAULT_INTERVAL = 180000;\n\n/**\n * Compare 2 given strings and return boolean\n * eg: \"foo\" and \"FOO\" => true\n * eg: \"foo\" and \"bar\" => false\n * eg: \"foo\" and 123 => false\n *\n * @param value1 - first string to compare\n * @param value2 - first string to compare\n * @returns true if 2 strings are identical when they are lowercase\n */\nexport function isEqualCaseInsensitive(\n value1: string,\n value2: string,\n): boolean {\n if (typeof value1 !== 'string' || typeof value2 !== 'string') {\n return false;\n }\n return value1.toLowerCase() === value2.toLowerCase();\n}\n\ntype LegacyToken = {\n name: string;\n logo: `${string}.svg`;\n symbol: string;\n decimals: number;\n erc20?: boolean;\n erc721?: boolean;\n};\n\ntype TokenDetectionMap = {\n [P in keyof TokenListMap]: Omit<TokenListMap[P], 'occurrences'>;\n};\n\nexport const STATIC_MAINNET_TOKEN_LIST = Object.entries<LegacyToken>(\n contractMap,\n).reduce<TokenDetectionMap>((acc, [base, contract]) => {\n const { logo, erc20, erc721, ...tokenMetadata } = contract;\n return {\n ...acc,\n [base.toLowerCase()]: {\n ...tokenMetadata,\n address: base.toLowerCase(),\n iconUrl: `images/contract/${logo}`,\n aggregators: [],\n },\n };\n}, {});\n\nexport const controllerName = 'TokenDetectionController';\n\nexport type TokenDetectionState = Record<never, never>;\n\nexport type TokenDetectionControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenDetectionState\n>;\n\nexport type TokenDetectionControllerActions =\n TokenDetectionControllerGetStateAction;\n\nexport type AllowedActions =\n | AccountsControllerGetSelectedAccountAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetNetworkConfigurationByNetworkClientId\n | NetworkControllerGetStateAction\n | GetTokenListState\n | KeyringControllerGetStateAction\n | PreferencesControllerGetStateAction\n | TokensControllerGetStateAction\n | TokensControllerAddDetectedTokensAction;\n\nexport type TokenDetectionControllerStateChangeEvent =\n ControllerStateChangeEvent<typeof controllerName, TokenDetectionState>;\n\nexport type TokenDetectionControllerEvents =\n TokenDetectionControllerStateChangeEvent;\n\nexport type AllowedEvents =\n | AccountsControllerSelectedAccountChangeEvent\n | NetworkControllerNetworkDidChangeEvent\n | TokenListStateChange\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n | PreferencesControllerStateChangeEvent;\n\nexport type TokenDetectionControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenDetectionControllerActions | AllowedActions,\n TokenDetectionControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Controller that passively polls on a set interval for Tokens auto detection\n * @property intervalId - Polling interval used to fetch new token rates\n * @property selectedAddress - Vault selected address\n * @property networkClientId - The network client ID of the current selected network\n * @property disabled - Boolean to track if network requests are blocked\n * @property isUnlocked - Boolean to track if the keyring state is unlocked\n * @property isDetectionEnabledFromPreferences - Boolean to track if detection is enabled from PreferencesController\n * @property isDetectionEnabledForNetwork - Boolean to track if detected is enabled for current network\n */\nexport class TokenDetectionController extends StaticIntervalPollingController<\n typeof controllerName,\n TokenDetectionState,\n TokenDetectionControllerMessenger\n> {\n #intervalId?: ReturnType<typeof setTimeout>;\n\n #selectedAddress: string;\n\n #networkClientId: NetworkClientId;\n\n #tokenList: TokenDetectionMap = {};\n\n #disabled: boolean;\n\n #isUnlocked: boolean;\n\n #isDetectionEnabledFromPreferences: boolean;\n\n #isDetectionEnabledForNetwork: boolean;\n\n readonly #getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n\n readonly #trackMetaMetricsEvent: (options: {\n event: string;\n category: string;\n properties: {\n tokens: string[];\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: string;\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: string;\n };\n }) => void;\n\n /**\n * Creates a TokenDetectionController instance.\n *\n * @param options - The controller options.\n * @param options.messenger - The controller messaging system.\n * @param options.disabled - If set to true, all network requests are blocked.\n * @param options.interval - Polling interval used to fetch new token rates\n * @param options.selectedAddress - Vault selected address\n * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.\n * @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.\n */\n constructor({\n selectedAddress,\n interval = DEFAULT_INTERVAL,\n disabled = true,\n getBalancesInSingleCall,\n trackMetaMetricsEvent,\n messenger,\n }: {\n selectedAddress?: string;\n interval?: number;\n disabled?: boolean;\n getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n trackMetaMetricsEvent: (options: {\n event: string;\n category: string;\n properties: {\n tokens: string[];\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: string;\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: string;\n };\n }) => void;\n messenger: TokenDetectionControllerMessenger;\n }) {\n super({\n name: controllerName,\n messenger,\n state: {},\n metadata: {},\n });\n\n this.#disabled = disabled;\n this.setIntervalLength(interval);\n\n this.#selectedAddress =\n selectedAddress ??\n this.messagingSystem.call('AccountsController:getSelectedAccount')\n .address;\n\n const { chainId, networkClientId } =\n this.#getCorrectChainIdAndNetworkClientId();\n this.#networkClientId = networkClientId;\n\n const { useTokenDetection: defaultUseTokenDetection } =\n this.messagingSystem.call('PreferencesController:getState');\n this.#isDetectionEnabledFromPreferences = defaultUseTokenDetection;\n this.#isDetectionEnabledForNetwork =\n isTokenDetectionSupportedForNetwork(chainId);\n\n this.#getBalancesInSingleCall = getBalancesInSingleCall;\n\n this.#trackMetaMetricsEvent = trackMetaMetricsEvent;\n\n const { isUnlocked } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n this.#isUnlocked = isUnlocked;\n\n this.#registerEventListeners();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system subscriptions to controller events.\n */\n #registerEventListeners() {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.messagingSystem.subscribe('KeyringController:unlock', async () => {\n this.#isUnlocked = true;\n await this.#restartTokenDetection();\n });\n\n this.messagingSystem.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n this.#stopPolling();\n });\n\n this.messagingSystem.subscribe(\n 'TokenListController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ tokenList }) => {\n const hasTokens = Object.keys(tokenList).length;\n\n if (hasTokens) {\n await this.#restartTokenDetection();\n }\n },\n );\n\n this.messagingSystem.subscribe(\n 'PreferencesController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ selectedAddress: newSelectedAddress, useTokenDetection }) => {\n const isSelectedAddressChanged =\n this.#selectedAddress !== newSelectedAddress;\n const isDetectionChangedFromPreferences =\n this.#isDetectionEnabledFromPreferences !== useTokenDetection;\n\n this.#selectedAddress = newSelectedAddress;\n this.#isDetectionEnabledFromPreferences = useTokenDetection;\n\n if (isSelectedAddressChanged || isDetectionChangedFromPreferences) {\n await this.#restartTokenDetection({\n selectedAddress: this.#selectedAddress,\n });\n }\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ address: newSelectedAddress }) => {\n const isSelectedAddressChanged =\n this.#selectedAddress !== newSelectedAddress;\n if (isSelectedAddressChanged) {\n this.#selectedAddress = newSelectedAddress;\n await this.#restartTokenDetection({\n selectedAddress: this.#selectedAddress,\n });\n }\n },\n );\n\n this.messagingSystem.subscribe(\n 'NetworkController:networkDidChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ selectedNetworkClientId }) => {\n const isNetworkClientIdChanged =\n this.#networkClientId !== selectedNetworkClientId;\n\n const { chainId: newChainId } =\n this.#getCorrectChainIdAndNetworkClientId(selectedNetworkClientId);\n this.#isDetectionEnabledForNetwork =\n isTokenDetectionSupportedForNetwork(newChainId);\n\n if (isNetworkClientIdChanged && this.#isDetectionEnabledForNetwork) {\n this.#networkClientId = selectedNetworkClientId;\n await this.#restartTokenDetection({\n networkClientId: this.#networkClientId,\n });\n }\n },\n );\n }\n\n /**\n * Allows controller to make active and passive polling requests\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Blocks controller from making network calls\n */\n disable(): void {\n this.#disabled = true;\n }\n\n /**\n * Internal isActive state\n * @type {boolean}\n */\n get isActive(): boolean {\n return !this.#disabled && this.#isUnlocked;\n }\n\n /**\n * Start polling for detected tokens.\n */\n async start(): Promise<void> {\n this.enable();\n await this.#startPolling();\n }\n\n /**\n * Stop polling for detected tokens.\n */\n stop(): void {\n this.disable();\n this.#stopPolling();\n }\n\n #stopPolling(): void {\n if (this.#intervalId) {\n clearInterval(this.#intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n async #startPolling(): Promise<void> {\n if (!this.isActive) {\n return;\n }\n this.#stopPolling();\n await this.detectTokens();\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#intervalId = setInterval(async () => {\n await this.detectTokens();\n }, this.getIntervalLength());\n }\n\n #getCorrectChainIdAndNetworkClientId(networkClientId?: NetworkClientId): {\n chainId: Hex;\n networkClientId: NetworkClientId;\n } {\n if (networkClientId) {\n const networkConfiguration = this.messagingSystem.call(\n 'NetworkController:getNetworkConfigurationByNetworkClientId',\n networkClientId,\n );\n if (networkConfiguration) {\n return {\n chainId: networkConfiguration.chainId,\n networkClientId,\n };\n }\n }\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return {\n chainId,\n networkClientId: selectedNetworkClientId,\n };\n }\n\n async _executePoll(\n networkClientId: NetworkClientId,\n options: { address: string },\n ): Promise<void> {\n if (!this.isActive) {\n return;\n }\n await this.detectTokens({\n networkClientId,\n selectedAddress: options.address,\n });\n }\n\n /**\n * Restart token detection polling period and call detectNewTokens\n * in case of address change or user session initialization.\n *\n * @param options - Options for restart token detection.\n * @param options.selectedAddress - the selectedAddress against which to detect for token balances\n * @param options.networkClientId - The ID of the network client to use.\n */\n async #restartTokenDetection({\n selectedAddress,\n networkClientId,\n }: {\n selectedAddress?: string;\n networkClientId?: NetworkClientId;\n } = {}): Promise<void> {\n await this.detectTokens({\n networkClientId,\n selectedAddress,\n });\n this.setIntervalLength(DEFAULT_INTERVAL);\n }\n\n /**\n * For each token in the token list provided by the TokenListController, checks the token's balance for the selected account address on the active network.\n * On mainnet, if token detection is disabled in preferences, ERC20 token auto detection will be triggered for each contract address in the legacy token list from the @metamask/contract-metadata repo.\n *\n * @param options - Options for token detection.\n * @param options.networkClientId - The ID of the network client to use.\n * @param options.selectedAddress - the selectedAddress against which to detect for token balances.\n */\n async detectTokens({\n networkClientId,\n selectedAddress,\n }: {\n networkClientId?: NetworkClientId;\n selectedAddress?: string;\n } = {}): Promise<void> {\n if (!this.isActive) {\n return;\n }\n\n const addressAgainstWhichToDetect =\n selectedAddress ?? this.#selectedAddress;\n const { chainId, networkClientId: selectedNetworkClientId } =\n this.#getCorrectChainIdAndNetworkClientId(networkClientId);\n const chainIdAgainstWhichToDetect = chainId;\n const networkClientIdAgainstWhichToDetect = selectedNetworkClientId;\n\n if (!isTokenDetectionSupportedForNetwork(chainIdAgainstWhichToDetect)) {\n return;\n }\n if (\n !this.#isDetectionEnabledFromPreferences &&\n chainIdAgainstWhichToDetect !== ChainId.mainnet\n ) {\n return;\n }\n const isTokenDetectionInactiveInMainnet =\n !this.#isDetectionEnabledFromPreferences &&\n chainIdAgainstWhichToDetect === ChainId.mainnet;\n const { tokensChainsCache } = this.messagingSystem.call(\n 'TokenListController:getState',\n );\n this.#tokenList = isTokenDetectionInactiveInMainnet\n ? STATIC_MAINNET_TOKEN_LIST\n : tokensChainsCache[chainIdAgainstWhichToDetect]?.data ?? {};\n\n for (const tokensSlice of this.#getSlicesOfTokensToDetect({\n chainId: chainIdAgainstWhichToDetect,\n selectedAddress: addressAgainstWhichToDetect,\n })) {\n await this.#addDetectedTokens({\n tokensSlice,\n selectedAddress: addressAgainstWhichToDetect,\n networkClientId: networkClientIdAgainstWhichToDetect,\n chainId: chainIdAgainstWhichToDetect,\n });\n }\n }\n\n #getSlicesOfTokensToDetect({\n chainId,\n selectedAddress,\n }: {\n chainId: Hex;\n selectedAddress: string;\n }): string[][] {\n const { allTokens, allDetectedTokens, allIgnoredTokens } =\n this.messagingSystem.call('TokensController:getState');\n const [tokensAddresses, detectedTokensAddresses, ignoredTokensAddresses] = [\n allTokens,\n allDetectedTokens,\n allIgnoredTokens,\n ].map((tokens) =>\n (tokens[chainId]?.[selectedAddress] ?? []).map((value) =>\n typeof value === 'string' ? value : value.address,\n ),\n );\n\n const tokensToDetect: string[] = [];\n for (const tokenAddress of Object.keys(this.#tokenList)) {\n if (\n [\n tokensAddresses,\n detectedTokensAddresses,\n ignoredTokensAddresses,\n ].every(\n (addresses) =>\n !addresses.find((address) =>\n isEqualCaseInsensitive(address, tokenAddress),\n ),\n )\n ) {\n tokensToDetect.push(tokenAddress);\n }\n }\n\n const slicesOfTokensToDetect = [];\n for (let i = 0, size = 1000; i < tokensToDetect.length; i += size) {\n slicesOfTokensToDetect.push(tokensToDetect.slice(i, i + size));\n }\n\n return slicesOfTokensToDetect;\n }\n\n async #addDetectedTokens({\n tokensSlice,\n selectedAddress,\n networkClientId,\n chainId,\n }: {\n tokensSlice: string[];\n selectedAddress: string;\n networkClientId: NetworkClientId;\n chainId: Hex;\n }): Promise<void> {\n await safelyExecute(async () => {\n const balances = await this.#getBalancesInSingleCall(\n selectedAddress,\n tokensSlice,\n networkClientId,\n );\n\n const tokensWithBalance: Token[] = [];\n const eventTokensDetails: string[] = [];\n for (const nonZeroTokenAddress of Object.keys(balances)) {\n const { decimals, symbol, aggregators, iconUrl, name } =\n this.#tokenList[nonZeroTokenAddress];\n eventTokensDetails.push(`${symbol} - ${nonZeroTokenAddress}`);\n tokensWithBalance.push({\n address: nonZeroTokenAddress,\n decimals,\n symbol,\n aggregators,\n image: iconUrl,\n isERC721: false,\n name,\n });\n }\n\n if (tokensWithBalance.length) {\n this.#trackMetaMetricsEvent({\n event: 'Token Detected',\n category: 'Wallet',\n properties: {\n tokens: eventTokensDetails,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: 'ERC20',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: 'TOKEN',\n },\n });\n\n await this.messagingSystem.call(\n 'TokensController:addDetectedTokens',\n tokensWithBalance,\n {\n selectedAddress,\n chainId,\n },\n );\n }\n });\n }\n}\n\nexport default TokenDetectionController;\n"]}
|
package/dist/index.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkFGAZXVKSjs = require('./chunk-FGAZXVKS.js');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
var _chunkV6DNVRODjs = require('./chunk-V6DNVROD.js');
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var _chunkRJBYLTY5js = require('./chunk-RJBYLTY5.js');
|
|
13
13
|
require('./chunk-XC3SOOGC.js');
|
|
14
14
|
|
|
15
15
|
|
|
@@ -41,10 +41,10 @@ var _chunk354SINOHjs = require('./chunk-354SINOH.js');
|
|
|
41
41
|
require('./chunk-RGHTNZQ6.js');
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
var
|
|
44
|
+
var _chunkNWVMFCSCjs = require('./chunk-NWVMFCSC.js');
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
var
|
|
47
|
+
var _chunkVZF43NDMjs = require('./chunk-VZF43NDM.js');
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
var _chunk7OZL6IDYjs = require('./chunk-7OZL6IDY.js');
|
|
@@ -79,5 +79,5 @@ require('./chunk-Z4BLTVTB.js');
|
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
exports.AccountTrackerController = _chunkHVOIBGYNjs.AccountTrackerController; exports.AssetsContractController = _chunkXSNGD5USjs.AssetsContractController; exports.CodefiTokenPricesServiceV2 = _chunkV6DNVRODjs.CodefiTokenPricesServiceV2; exports.Cryptocurrency = _chunkF6L3DFOZjs.Cryptocurrency; exports.CurrencyRateController = _chunkT5ZX5BV7js.CurrencyRateController; exports.MISSING_PROVIDER_ERROR = _chunkXSNGD5USjs.MISSING_PROVIDER_ERROR; exports.NftController = _chunk7JWDWDXTjs.NftController; exports.NftDetectionController = _chunk354SINOHjs.NftDetectionController; exports.RatesController = _chunkF6L3DFOZjs.RatesController; exports.SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID = _chunkXSNGD5USjs.SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID; exports.SUPPORTED_CHAIN_IDS = _chunkV6DNVRODjs.SUPPORTED_CHAIN_IDS; exports.TokenBalancesController =
|
|
82
|
+
exports.AccountTrackerController = _chunkHVOIBGYNjs.AccountTrackerController; exports.AssetsContractController = _chunkXSNGD5USjs.AssetsContractController; exports.CodefiTokenPricesServiceV2 = _chunkV6DNVRODjs.CodefiTokenPricesServiceV2; exports.Cryptocurrency = _chunkF6L3DFOZjs.Cryptocurrency; exports.CurrencyRateController = _chunkT5ZX5BV7js.CurrencyRateController; exports.MISSING_PROVIDER_ERROR = _chunkXSNGD5USjs.MISSING_PROVIDER_ERROR; exports.NftController = _chunk7JWDWDXTjs.NftController; exports.NftDetectionController = _chunk354SINOHjs.NftDetectionController; exports.RatesController = _chunkF6L3DFOZjs.RatesController; exports.SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID = _chunkXSNGD5USjs.SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID; exports.SUPPORTED_CHAIN_IDS = _chunkV6DNVRODjs.SUPPORTED_CHAIN_IDS; exports.TokenBalancesController = _chunkNWVMFCSCjs.TokenBalancesController; exports.TokenDetectionController = _chunkVZF43NDMjs.TokenDetectionController; exports.TokenListController = _chunk7OZL6IDYjs.TokenListController; exports.TokenRatesController = _chunkFGAZXVKSjs.TokenRatesController; exports.TokensController = _chunkRJBYLTY5js.TokensController; exports.fetchTokenContractExchangeRates = _chunkNYVA7ZTQjs.fetchTokenContractExchangeRates; exports.formatIconUrlWithProxy = _chunkNYVA7ZTQjs.formatIconUrlWithProxy; exports.getDefaultNftControllerState = _chunk7JWDWDXTjs.getDefaultNftControllerState; exports.getDefaultTokenRatesControllerState = _chunkFGAZXVKSjs.getDefaultTokenRatesControllerState; exports.getFormattedIpfsUrl = _chunkNYVA7ZTQjs.getFormattedIpfsUrl; exports.isTokenDetectionSupportedForNetwork = _chunkNYVA7ZTQjs.isTokenDetectionSupportedForNetwork;
|
|
83
83
|
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
CHANGED
|
@@ -2,14 +2,14 @@ import "./chunk-27KOXCQK.mjs";
|
|
|
2
2
|
import {
|
|
3
3
|
TokenRatesController,
|
|
4
4
|
getDefaultTokenRatesControllerState
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-P3O5CVAH.mjs";
|
|
6
6
|
import {
|
|
7
7
|
CodefiTokenPricesServiceV2,
|
|
8
8
|
SUPPORTED_CHAIN_IDS
|
|
9
9
|
} from "./chunk-XQO3EG4J.mjs";
|
|
10
10
|
import {
|
|
11
11
|
TokensController
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UVE4XY5Y.mjs";
|
|
13
13
|
import "./chunk-JYHAAA6W.mjs";
|
|
14
14
|
import {
|
|
15
15
|
Cryptocurrency,
|
|
@@ -41,10 +41,10 @@ import {
|
|
|
41
41
|
import "./chunk-CP3HC7AQ.mjs";
|
|
42
42
|
import {
|
|
43
43
|
TokenBalancesController
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-OEEFNXR7.mjs";
|
|
45
45
|
import {
|
|
46
46
|
TokenDetectionController
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-3K3LE2CZ.mjs";
|
|
48
48
|
import {
|
|
49
49
|
TokenListController
|
|
50
50
|
} from "./chunk-Y45HQET7.mjs";
|