@metamask-previews/assets-controllers 28.0.0-preview-61ace68c → 28.0.0-preview-cb17e99
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/NftController.js +2 -2
- package/dist/NftController.mjs +1 -1
- package/dist/NftDetectionController.js +2 -2
- package/dist/NftDetectionController.mjs +1 -1
- 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-4LY47RPI.mjs → chunk-65FXYE6I.mjs} +11 -5
- package/dist/chunk-65FXYE6I.mjs.map +1 -0
- package/dist/{chunk-6XOM7KOQ.mjs → chunk-6VBIGDGQ.mjs} +75 -22
- package/dist/chunk-6VBIGDGQ.mjs.map +1 -0
- package/dist/{chunk-TFAPRTSR.mjs → chunk-ASFD56OL.mjs} +10 -37
- package/dist/chunk-ASFD56OL.mjs.map +1 -0
- package/dist/{chunk-IOQX3VTD.js → chunk-JZGMPO5X.js} +25 -13
- package/dist/chunk-JZGMPO5X.js.map +1 -0
- package/dist/{chunk-RZPEI5OL.js → chunk-KM3J4DO6.js} +54 -133
- package/dist/chunk-KM3J4DO6.js.map +1 -0
- package/dist/{chunk-I53XGBU3.js → chunk-KYJXDVWZ.js} +46 -21
- package/dist/chunk-KYJXDVWZ.js.map +1 -0
- package/dist/{chunk-LD4GC7OR.js → chunk-N4J3LGOF.js} +11 -5
- package/dist/chunk-N4J3LGOF.js.map +1 -0
- package/dist/{chunk-D33ADI5V.mjs → chunk-S6CZP74C.mjs} +54 -133
- package/dist/chunk-S6CZP74C.mjs.map +1 -0
- package/dist/{chunk-SOK5YX7I.js → chunk-TDK4U47T.js} +75 -22
- package/dist/chunk-TDK4U47T.js.map +1 -0
- package/dist/{chunk-OWTCG2N3.mjs → chunk-W4JCZ6UQ.mjs} +25 -13
- package/dist/chunk-W4JCZ6UQ.mjs.map +1 -0
- package/dist/{chunk-EBX646YG.js → chunk-X2MMIBYW.js} +10 -37
- package/dist/chunk-X2MMIBYW.js.map +1 -0
- package/dist/{chunk-D3PCUDTX.mjs → chunk-YUKHDFUN.mjs} +46 -21
- package/dist/chunk-YUKHDFUN.mjs.map +1 -0
- package/dist/index.js +7 -7
- package/dist/index.mjs +6 -6
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/NftController.d.ts +5 -7
- package/dist/types/NftController.d.ts.map +1 -1
- package/dist/types/NftDetectionController.d.ts +6 -12
- package/dist/types/NftDetectionController.d.ts.map +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 +5 -5
- package/dist/types/TokenDetectionController.d.ts.map +1 -1
- package/dist/types/TokenRatesController.d.ts +10 -7
- package/dist/types/TokenRatesController.d.ts.map +1 -1
- package/dist/types/TokensController.d.ts +5 -5
- package/dist/types/TokensController.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4LY47RPI.mjs.map +0 -1
- package/dist/chunk-6XOM7KOQ.mjs.map +0 -1
- package/dist/chunk-D33ADI5V.mjs.map +0 -1
- package/dist/chunk-D3PCUDTX.mjs.map +0 -1
- package/dist/chunk-EBX646YG.js.map +0 -1
- package/dist/chunk-I53XGBU3.js.map +0 -1
- package/dist/chunk-IOQX3VTD.js.map +0 -1
- package/dist/chunk-LD4GC7OR.js.map +0 -1
- package/dist/chunk-OWTCG2N3.mjs.map +0 -1
- package/dist/chunk-RZPEI5OL.js.map +0 -1
- package/dist/chunk-SOK5YX7I.js.map +0 -1
- package/dist/chunk-TFAPRTSR.mjs.map +0 -1
package/dist/NftController.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkKM3J4DO6js = require('./chunk-KM3J4DO6.js');
|
|
6
6
|
require('./chunk-RGHTNZQ6.js');
|
|
7
7
|
require('./chunk-LS6R3HQL.js');
|
|
8
8
|
require('./chunk-Z4BLTVTB.js');
|
|
@@ -10,5 +10,5 @@ require('./chunk-Z4BLTVTB.js');
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
exports.NftController =
|
|
13
|
+
exports.NftController = _chunkKM3J4DO6js.NftController; exports.default = _chunkKM3J4DO6js.NftController_default; exports.getDefaultNftState = _chunkKM3J4DO6js.getDefaultNftState;
|
|
14
14
|
//# sourceMappingURL=NftController.js.map
|
package/dist/NftController.mjs
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkX2MMIBYWjs = require('./chunk-X2MMIBYW.js');
|
|
6
6
|
require('./chunk-RGHTNZQ6.js');
|
|
7
7
|
require('./chunk-Z4BLTVTB.js');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
exports.BlockaidResultType =
|
|
12
|
+
exports.BlockaidResultType = _chunkX2MMIBYWjs.BlockaidResultType; exports.NftDetectionController = _chunkX2MMIBYWjs.NftDetectionController; exports.default = _chunkX2MMIBYWjs.NftDetectionController_default;
|
|
13
13
|
//# sourceMappingURL=NftDetectionController.js.map
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkN4J3LGOFjs = require('./chunk-N4J3LGOF.js');
|
|
6
6
|
require('./chunk-Z4BLTVTB.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
exports.TokenBalancesController =
|
|
11
|
+
exports.TokenBalancesController = _chunkN4J3LGOFjs.TokenBalancesController; exports.default = _chunkN4J3LGOFjs.TokenBalancesController_default; exports.getDefaultTokenBalancesState = _chunkN4J3LGOFjs.getDefaultTokenBalancesState;
|
|
12
12
|
//# sourceMappingURL=TokenBalancesController.js.map
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunkKYJXDVWZjs = require('./chunk-KYJXDVWZ.js');
|
|
8
8
|
require('./chunk-LS6R3HQL.js');
|
|
9
9
|
require('./chunk-Z4BLTVTB.js');
|
|
10
10
|
|
|
@@ -13,5 +13,5 @@ require('./chunk-Z4BLTVTB.js');
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
exports.STATIC_MAINNET_TOKEN_LIST =
|
|
16
|
+
exports.STATIC_MAINNET_TOKEN_LIST = _chunkKYJXDVWZjs.STATIC_MAINNET_TOKEN_LIST; exports.TokenDetectionController = _chunkKYJXDVWZjs.TokenDetectionController; exports.controllerName = _chunkKYJXDVWZjs.controllerName; exports.default = _chunkKYJXDVWZjs.TokenDetectionController_default; exports.isEqualCaseInsensitive = _chunkKYJXDVWZjs.isEqualCaseInsensitive;
|
|
17
17
|
//# sourceMappingURL=TokenDetectionController.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var _chunkJZGMPO5Xjs = require('./chunk-JZGMPO5X.js');
|
|
5
5
|
require('./chunk-DYH5P3VY.js');
|
|
6
6
|
require('./chunk-LS6R3HQL.js');
|
|
7
7
|
require('./chunk-Z4BLTVTB.js');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
exports.TokenRatesController =
|
|
11
|
+
exports.TokenRatesController = _chunkJZGMPO5Xjs.TokenRatesController; exports.default = _chunkJZGMPO5Xjs.TokenRatesController_default;
|
|
12
12
|
//# sourceMappingURL=TokenRatesController.js.map
|
package/dist/TokensController.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkTDK4U47Tjs = require('./chunk-TDK4U47T.js');
|
|
6
6
|
require('./chunk-3ZHN4GFT.js');
|
|
7
7
|
require('./chunk-BO2WZDUM.js');
|
|
8
8
|
require('./chunk-OHSQRYVL.js');
|
|
@@ -12,5 +12,5 @@ require('./chunk-Z4BLTVTB.js');
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
exports.TokensController =
|
|
15
|
+
exports.TokensController = _chunkTDK4U47Tjs.TokensController; exports.default = _chunkTDK4U47Tjs.TokensController_default; exports.getDefaultTokensState = _chunkTDK4U47Tjs.getDefaultTokensState;
|
|
16
16
|
//# sourceMappingURL=TokensController.js.map
|
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
} from "./chunk-XUI43LEZ.mjs";
|
|
6
6
|
|
|
7
7
|
// src/TokenBalancesController.ts
|
|
8
|
+
import {
|
|
9
|
+
isEVMAccount
|
|
10
|
+
} from "@metamask/accounts-controller";
|
|
8
11
|
import {
|
|
9
12
|
BaseController
|
|
10
13
|
} from "@metamask/base-controller";
|
|
@@ -103,15 +106,18 @@ var TokenBalancesController = class extends BaseController {
|
|
|
103
106
|
if (__privateGet(this, _disabled)) {
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
109
|
+
const selectedInternalAccount = this.messagingSystem.call(
|
|
110
|
+
"AccountsController:getSelectedAccount"
|
|
111
|
+
);
|
|
112
|
+
if (!isEVMAccount(selectedInternalAccount)) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
106
115
|
const newContractBalances = {};
|
|
107
116
|
for (const token of __privateGet(this, _tokens)) {
|
|
108
117
|
const { address } = token;
|
|
109
|
-
const { selectedAddress } = this.messagingSystem.call(
|
|
110
|
-
"PreferencesController:getState"
|
|
111
|
-
);
|
|
112
118
|
try {
|
|
113
119
|
newContractBalances[address] = toHex(
|
|
114
|
-
await __privateGet(this, _getERC20BalanceOf).call(this, address,
|
|
120
|
+
await __privateGet(this, _getERC20BalanceOf).call(this, address, selectedInternalAccount.address)
|
|
115
121
|
);
|
|
116
122
|
token.balanceError = null;
|
|
117
123
|
} catch (error) {
|
|
@@ -136,4 +142,4 @@ export {
|
|
|
136
142
|
TokenBalancesController,
|
|
137
143
|
TokenBalancesController_default
|
|
138
144
|
};
|
|
139
|
-
//# sourceMappingURL=chunk-
|
|
145
|
+
//# sourceMappingURL=chunk-65FXYE6I.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/TokenBalancesController.ts"],"sourcesContent":["import {\n isEVMAccount,\n type AccountsControllerGetSelectedAccountAction,\n} from '@metamask/accounts-controller';\nimport {\n type RestrictedControllerMessenger,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n BaseController,\n} from '@metamask/base-controller';\nimport { safelyExecute, toHex } from '@metamask/controller-utils';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport type { Token } from './TokenRatesController';\nimport type { TokensControllerStateChangeEvent } from './TokensController';\n\nconst DEFAULT_INTERVAL = 180000;\n\nconst controllerName = 'TokenBalancesController';\n\nconst metadata = {\n contractBalances: { persist: true, anonymous: false },\n};\n\n/**\n * Token balances controller options\n * @property interval - Polling interval used to fetch new token balances.\n * @property tokens - List of tokens to track balances for.\n * @property disabled - If set to true, all tracked tokens contract balances updates are blocked.\n * @property getERC20BalanceOf - Gets the balance of the given account at the given contract address.\n */\ntype TokenBalancesControllerOptions = {\n interval?: number;\n tokens?: Token[];\n disabled?: boolean;\n getERC20BalanceOf: AssetsContractController['getERC20BalanceOf'];\n messenger: TokenBalancesControllerMessenger;\n state?: Partial<TokenBalancesControllerState>;\n};\n\n/**\n * Represents a mapping of hash token contract addresses to their balances.\n */\ntype ContractBalances = Record<string, string>;\n\n/**\n * Token balances controller state\n * @property contractBalances - Hash of token contract addresses to balances\n */\nexport type TokenBalancesControllerState = {\n contractBalances: ContractBalances;\n};\n\nexport type TokenBalancesControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenBalancesControllerState\n>;\n\nexport type TokenBalancesControllerActions =\n TokenBalancesControllerGetStateAction;\n\nexport type AllowedActions = AccountsControllerGetSelectedAccountAction;\n\nexport type TokenBalancesControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n TokenBalancesControllerState\n >;\n\nexport type TokenBalancesControllerEvents =\n TokenBalancesControllerStateChangeEvent;\n\nexport type AllowedEvents = TokensControllerStateChangeEvent;\n\nexport type TokenBalancesControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenBalancesControllerActions | AllowedActions,\n TokenBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Get the default TokenBalancesController state.\n *\n * @returns The default TokenBalancesController state.\n */\nexport function getDefaultTokenBalancesState(): TokenBalancesControllerState {\n return {\n contractBalances: {},\n };\n}\n\n/**\n * Controller that passively polls on a set interval token balances\n * for tokens stored in the TokensController\n */\nexport class TokenBalancesController extends BaseController<\n typeof controllerName,\n TokenBalancesControllerState,\n TokenBalancesControllerMessenger\n> {\n #handle?: ReturnType<typeof setTimeout>;\n\n #getERC20BalanceOf: AssetsContractController['getERC20BalanceOf'];\n\n #interval: number;\n\n #tokens: Token[];\n\n #disabled: boolean;\n\n /**\n * Construct a Token Balances Controller.\n *\n * @param options - The controller options.\n * @param options.interval - Polling interval used to fetch new token balances.\n * @param options.tokens - List of tokens to track balances for.\n * @param options.disabled - If set to true, all tracked tokens contract balances updates are blocked.\n * @param options.getERC20BalanceOf - Gets the balance of the given account at the given contract address.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller restricted messenger.\n */\n constructor({\n interval = DEFAULT_INTERVAL,\n tokens = [],\n disabled = false,\n getERC20BalanceOf,\n messenger,\n state = {},\n }: TokenBalancesControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultTokenBalancesState(),\n ...state,\n },\n });\n\n this.#disabled = disabled;\n this.#interval = interval;\n this.#tokens = tokens;\n\n this.messagingSystem.subscribe(\n 'TokensController:stateChange',\n ({ tokens: newTokens, detectedTokens }) => {\n this.#tokens = [...newTokens, ...detectedTokens];\n this.updateBalances();\n },\n );\n\n this.#getERC20BalanceOf = getERC20BalanceOf;\n\n this.poll();\n }\n\n /**\n * Allows controller to update tracked tokens contract balances.\n */\n enable() {\n this.#disabled = false;\n }\n\n /**\n * Blocks controller from updating tracked tokens contract balances.\n */\n disable() {\n this.#disabled = true;\n }\n\n /**\n * Starts a new polling interval.\n *\n * @param interval - Polling interval used to fetch new token balances.\n */\n async poll(interval?: number): Promise<void> {\n if (interval) {\n this.#interval = interval;\n }\n\n if (this.#handle) {\n clearTimeout(this.#handle);\n }\n\n await safelyExecute(() => this.updateBalances());\n\n this.#handle = setTimeout(() => {\n this.poll(this.#interval);\n }, this.#interval);\n }\n\n /**\n * Updates balances for all tokens.\n */\n async updateBalances() {\n if (this.#disabled) {\n return;\n }\n const selectedInternalAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedAccount',\n );\n if (!isEVMAccount(selectedInternalAccount)) {\n return;\n }\n\n const newContractBalances: ContractBalances = {};\n for (const token of this.#tokens) {\n const { address } = token;\n\n try {\n newContractBalances[address] = toHex(\n await this.#getERC20BalanceOf(\n address,\n selectedInternalAccount.address,\n ),\n );\n token.balanceError = null;\n } catch (error) {\n newContractBalances[address] = toHex(0);\n token.balanceError = error;\n }\n }\n\n this.update((state) => {\n state.contractBalances = newContractBalances;\n });\n }\n}\n\nexport default TokenBalancesController;\n"],"mappings":";;;;;;;AAAA;AAAA,EACE;AAAA,OAEK;AACP;AAAA,EAIE;AAAA,OACK;AACP,SAAS,eAAe,aAAa;AAMrC,IAAM,mBAAmB;AAEzB,IAAM,iBAAiB;AAEvB,IAAM,WAAW;AAAA,EACf,kBAAkB,EAAE,SAAS,MAAM,WAAW,MAAM;AACtD;AAiEO,SAAS,+BAA6D;AAC3E,SAAO;AAAA,IACL,kBAAkB,CAAC;AAAA,EACrB;AACF;AA3FA;AAiGO,IAAM,0BAAN,cAAsC,eAI3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,YAAY;AAAA,IACV,WAAW;AAAA,IACX,SAAS,CAAC;AAAA,IACV,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,QAAQ,CAAC;AAAA,EACX,GAAmC;AACjC,UAAM;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,OAAO;AAAA,QACL,GAAG,6BAA6B;AAAA,QAChC,GAAG;AAAA,MACL;AAAA,IACF,CAAC;AArCH;AAEA;AAEA;AAEA;AAEA;AA+BE,uBAAK,WAAY;AACjB,uBAAK,WAAY;AACjB,uBAAK,SAAU;AAEf,SAAK,gBAAgB;AAAA,MACnB;AAAA,MACA,CAAC,EAAE,QAAQ,WAAW,eAAe,MAAM;AACzC,2BAAK,SAAU,CAAC,GAAG,WAAW,GAAG,cAAc;AAC/C,aAAK,eAAe;AAAA,MACtB;AAAA,IACF;AAEA,uBAAK,oBAAqB;AAE1B,SAAK,KAAK;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS;AACP,uBAAK,WAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,uBAAK,WAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK,UAAkC;AAC3C,QAAI,UAAU;AACZ,yBAAK,WAAY;AAAA,IACnB;AAEA,QAAI,mBAAK,UAAS;AAChB,mBAAa,mBAAK,QAAO;AAAA,IAC3B;AAEA,UAAM,cAAc,MAAM,KAAK,eAAe,CAAC;AAE/C,uBAAK,SAAU,WAAW,MAAM;AAC9B,WAAK,KAAK,mBAAK,UAAS;AAAA,IAC1B,GAAG,mBAAK,UAAS;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB;AACrB,QAAI,mBAAK,YAAW;AAClB;AAAA,IACF;AACA,UAAM,0BAA0B,KAAK,gBAAgB;AAAA,MACnD;AAAA,IACF;AACA,QAAI,CAAC,aAAa,uBAAuB,GAAG;AAC1C;AAAA,IACF;AAEA,UAAM,sBAAwC,CAAC;AAC/C,eAAW,SAAS,mBAAK,UAAS;AAChC,YAAM,EAAE,QAAQ,IAAI;AAEpB,UAAI;AACF,4BAAoB,OAAO,IAAI;AAAA,UAC7B,MAAM,mBAAK,oBAAL,WACJ,SACA,wBAAwB;AAAA,QAE5B;AACA,cAAM,eAAe;AAAA,MACvB,SAAS,OAAO;AACd,4BAAoB,OAAO,IAAI,MAAM,CAAC;AACtC,cAAM,eAAe;AAAA,MACvB;AAAA,IACF;AAEA,SAAK,OAAO,CAAC,UAAU;AACrB,YAAM,mBAAmB;AAAA,IAC3B,CAAC;AAAA,EACH;AACF;AA/HE;AAEA;AAEA;AAEA;AAEA;AAyHF,IAAO,kCAAQ;","names":[]}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
// src/TokensController.ts
|
|
17
17
|
import { Contract } from "@ethersproject/contracts";
|
|
18
18
|
import { Web3Provider } from "@ethersproject/providers";
|
|
19
|
+
import { isEVMAccount } from "@metamask/accounts-controller";
|
|
19
20
|
import { BaseControllerV1 } from "@metamask/base-controller";
|
|
20
21
|
import contractsMap from "@metamask/contract-metadata";
|
|
21
22
|
import {
|
|
@@ -72,7 +73,7 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
72
73
|
*/
|
|
73
74
|
this.name = "TokensController";
|
|
74
75
|
this.defaultConfig = {
|
|
75
|
-
|
|
76
|
+
selectedAccountId: "",
|
|
76
77
|
chainId: initialChainId,
|
|
77
78
|
provider: void 0,
|
|
78
79
|
...config
|
|
@@ -89,15 +90,18 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
89
90
|
this.addDetectedTokens.bind(this)
|
|
90
91
|
);
|
|
91
92
|
this.messagingSystem.subscribe(
|
|
92
|
-
"
|
|
93
|
-
(
|
|
93
|
+
"AccountsController:selectedAccountChange",
|
|
94
|
+
(internalAccount) => {
|
|
95
|
+
this.configure({ selectedAccountId: internalAccount.id });
|
|
96
|
+
if (!isEVMAccount(internalAccount)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
94
99
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
95
100
|
const { chainId } = this.config;
|
|
96
|
-
this.configure({ selectedAddress });
|
|
97
101
|
this.update({
|
|
98
|
-
tokens: allTokens[chainId]?.[
|
|
99
|
-
ignoredTokens: allIgnoredTokens[chainId]?.[
|
|
100
|
-
detectedTokens: allDetectedTokens[chainId]?.[
|
|
102
|
+
tokens: allTokens[chainId]?.[internalAccount.address] ?? [],
|
|
103
|
+
ignoredTokens: allIgnoredTokens[chainId]?.[internalAccount.address] ?? [],
|
|
104
|
+
detectedTokens: allDetectedTokens[chainId]?.[internalAccount.address] ?? []
|
|
101
105
|
});
|
|
102
106
|
}
|
|
103
107
|
);
|
|
@@ -105,15 +109,22 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
105
109
|
"NetworkController:networkDidChange",
|
|
106
110
|
({ providerConfig }) => {
|
|
107
111
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
108
|
-
const {
|
|
112
|
+
const { selectedAccountId } = this.config;
|
|
113
|
+
const selectedInternalAccount = this.messagingSystem.call(
|
|
114
|
+
"AccountsController:getAccount",
|
|
115
|
+
selectedAccountId
|
|
116
|
+
);
|
|
109
117
|
const { chainId } = providerConfig;
|
|
110
118
|
this.abortController.abort();
|
|
111
119
|
this.abortController = new AbortController();
|
|
112
120
|
this.configure({ chainId });
|
|
121
|
+
if (!selectedInternalAccount || !isEVMAccount(selectedInternalAccount)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
113
124
|
this.update({
|
|
114
|
-
tokens: allTokens[chainId]?.[
|
|
115
|
-
ignoredTokens: allIgnoredTokens[chainId]?.[
|
|
116
|
-
detectedTokens: allDetectedTokens[chainId]?.[
|
|
125
|
+
tokens: allTokens[chainId]?.[selectedInternalAccount.address] || [],
|
|
126
|
+
ignoredTokens: allIgnoredTokens[chainId]?.[selectedInternalAccount.address] || [],
|
|
127
|
+
detectedTokens: allDetectedTokens[chainId]?.[selectedInternalAccount.address] || []
|
|
117
128
|
});
|
|
118
129
|
}
|
|
119
130
|
);
|
|
@@ -170,7 +181,7 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
170
181
|
interactingAddress,
|
|
171
182
|
networkClientId
|
|
172
183
|
}) {
|
|
173
|
-
const { chainId,
|
|
184
|
+
const { chainId, selectedAccountId } = this.config;
|
|
174
185
|
const releaseLock = await this.mutex.acquire();
|
|
175
186
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
176
187
|
let currentChainId = chainId;
|
|
@@ -180,8 +191,16 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
180
191
|
networkClientId
|
|
181
192
|
).configuration.chainId;
|
|
182
193
|
}
|
|
183
|
-
const
|
|
184
|
-
|
|
194
|
+
const internalAccount = this.messagingSystem.call(
|
|
195
|
+
"AccountsController:getAccount",
|
|
196
|
+
selectedAccountId
|
|
197
|
+
);
|
|
198
|
+
if (!internalAccount || !isEVMAccount(internalAccount)) {
|
|
199
|
+
releaseLock();
|
|
200
|
+
return [];
|
|
201
|
+
}
|
|
202
|
+
const accountAddress = interactingAddress || internalAccount.address;
|
|
203
|
+
const isInteractingWithWalletAccount = accountAddress === internalAccount.address;
|
|
185
204
|
try {
|
|
186
205
|
address = toChecksumHexAddress(address);
|
|
187
206
|
const tokens = allTokens[currentChainId]?.[accountAddress] || [];
|
|
@@ -357,8 +376,16 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
357
376
|
*/
|
|
358
377
|
async addDetectedTokens(incomingDetectedTokens, detectionDetails) {
|
|
359
378
|
const releaseLock = await this.mutex.acquire();
|
|
379
|
+
const internalAccount = this.messagingSystem.call(
|
|
380
|
+
"AccountsController:getAccount",
|
|
381
|
+
this.config.selectedAccountId
|
|
382
|
+
);
|
|
383
|
+
if (!internalAccount || !isEVMAccount(internalAccount)) {
|
|
384
|
+
releaseLock();
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
360
387
|
const chainId = detectionDetails?.chainId ?? this.config.chainId;
|
|
361
|
-
const accountAddress = detectionDetails?.selectedAddress ??
|
|
388
|
+
const accountAddress = detectionDetails?.selectedAddress ?? internalAccount.address;
|
|
362
389
|
const { allTokens, allDetectedTokens, allIgnoredTokens } = this.state;
|
|
363
390
|
let newTokens = [...allTokens?.[chainId]?.[accountAddress] ?? []];
|
|
364
391
|
let newDetectedTokens = [
|
|
@@ -412,9 +439,17 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
412
439
|
interactingChainId: chainId
|
|
413
440
|
}
|
|
414
441
|
);
|
|
415
|
-
const { chainId: currentChain,
|
|
416
|
-
|
|
417
|
-
|
|
442
|
+
const { chainId: currentChain, selectedAccountId: currentAccountId } = this.config;
|
|
443
|
+
const currentInternalAccount = this.messagingSystem.call(
|
|
444
|
+
"AccountsController:getAccount",
|
|
445
|
+
currentAccountId
|
|
446
|
+
);
|
|
447
|
+
if (!currentInternalAccount || !isEVMAccount(currentInternalAccount)) {
|
|
448
|
+
releaseLock();
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
newTokens = newAllTokens?.[currentChain]?.[currentInternalAccount.address] || [];
|
|
452
|
+
newDetectedTokens = newAllDetectedTokens?.[currentChain]?.[currentInternalAccount.address] || [];
|
|
418
453
|
this.update({
|
|
419
454
|
tokens: newTokens,
|
|
420
455
|
allTokens: newAllTokens,
|
|
@@ -525,6 +560,13 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
525
560
|
if (!isValidHexAddress(asset.address)) {
|
|
526
561
|
throw rpcErrors.invalidParams(`Invalid address "${asset.address}"`);
|
|
527
562
|
}
|
|
563
|
+
const selectedAccount = this.messagingSystem.call(
|
|
564
|
+
"AccountsController:getAccount",
|
|
565
|
+
this.config.selectedAccountId
|
|
566
|
+
);
|
|
567
|
+
if (!selectedAccount || !isEVMAccount(selectedAccount)) {
|
|
568
|
+
throw new Error(`Account is not an EVM account`);
|
|
569
|
+
}
|
|
528
570
|
if (await this._detectIsERC721(asset.address, networkClientId)) {
|
|
529
571
|
throw rpcErrors.invalidParams(
|
|
530
572
|
`Contract ${asset.address} must match type ${type}, but was detected as ${ERC721}`
|
|
@@ -590,7 +632,7 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
590
632
|
id: this._generateRandomId(),
|
|
591
633
|
time: Date.now(),
|
|
592
634
|
type,
|
|
593
|
-
interactingAddress: interactingAddress ||
|
|
635
|
+
interactingAddress: interactingAddress || selectedAccount.address
|
|
594
636
|
};
|
|
595
637
|
await this._requestApproval(suggestedAssetMeta);
|
|
596
638
|
const { address, symbol, decimals, name, image } = asset;
|
|
@@ -625,8 +667,19 @@ var TokensController = class extends BaseControllerV1 {
|
|
|
625
667
|
interactingChainId
|
|
626
668
|
} = params;
|
|
627
669
|
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
|
|
628
|
-
const { chainId,
|
|
629
|
-
const
|
|
670
|
+
const { chainId, selectedAccountId } = this.config;
|
|
671
|
+
const selectedInternalAccount = this.messagingSystem.call(
|
|
672
|
+
"AccountsController:getAccount",
|
|
673
|
+
selectedAccountId
|
|
674
|
+
);
|
|
675
|
+
if (!selectedInternalAccount || !isEVMAccount(selectedInternalAccount)) {
|
|
676
|
+
return {
|
|
677
|
+
newAllTokens: allTokens,
|
|
678
|
+
newAllIgnoredTokens: allIgnoredTokens,
|
|
679
|
+
newAllDetectedTokens: allDetectedTokens
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
const userAddressToAddTokens = interactingAddress ?? selectedInternalAccount.address;
|
|
630
683
|
const chainIdToAddTokens = interactingChainId ?? chainId;
|
|
631
684
|
let newAllTokens = allTokens;
|
|
632
685
|
if (newTokens?.length || newTokens && allTokens && allTokens[chainIdToAddTokens] && allTokens[chainIdToAddTokens][userAddressToAddTokens]) {
|
|
@@ -701,4 +754,4 @@ export {
|
|
|
701
754
|
TokensController,
|
|
702
755
|
TokensController_default
|
|
703
756
|
};
|
|
704
|
-
//# sourceMappingURL=chunk-
|
|
757
|
+
//# sourceMappingURL=chunk-6VBIGDGQ.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 {\n AccountsControllerGetAccountAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport { isEVMAccount } from '@metamask/accounts-controller';\nimport type { AddApprovalRequest } from '@metamask/approval-controller';\nimport type {\n BaseConfig,\n BaseState,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseControllerV1 } 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 Provider,\n} from '@metamask/network-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { EventEmitter } from 'events';\nimport type { Patch } from 'immer/dist/immer';\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 TokensConfig\n *\n * Tokens controller configuration\n * @property selectedAccountId - Vault selected address\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokensConfig extends BaseConfig {\n selectedAccountId: string;\n chainId: Hex;\n provider: Provider | undefined;\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 type TokensState = {\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\nexport type TokensControllerActions =\n | TokensControllerGetStateAction\n | TokensControllerAddDetectedTokensAction;\n\n// TODO: Once `TokensController` is upgraded to V2, rewrite this type using the `ControllerGetStateAction` type, which constrains `TokensState` as `Record<string, Json>`.\nexport type TokensControllerGetStateAction = {\n type: `${typeof controllerName}:getState`;\n handler: () => TokensState;\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 | AccountsControllerGetAccountAction;\n\n// TODO: Once `TokensController` is upgraded to V2, rewrite this type using the `ControllerStateChangeEvent` type, which constrains `TokensState` as `Record<string, Json>`.\nexport type TokensControllerStateChangeEvent = {\n type: `${typeof controllerName}:stateChange`;\n payload: [TokensState, Patch[]];\n};\n\nexport type TokensControllerEvents = TokensControllerStateChangeEvent;\n\nexport type AllowedEvents =\n | NetworkControllerNetworkDidChangeEvent\n | TokenListStateChange\n | AccountsControllerSelectedAccountChangeEvent;\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 = (): TokensState => {\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 BaseControllerV1<\n TokensConfig,\n TokensState & BaseState\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 /**\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.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 config,\n state,\n messenger,\n }: {\n chainId: Hex;\n config?: Partial<TokensConfig>;\n state?: Partial<TokensState>;\n messenger: TokensControllerMessenger;\n }) {\n super(config, state);\n\n this.defaultConfig = {\n selectedAccountId: '',\n chainId: initialChainId,\n provider: undefined,\n ...config,\n };\n\n this.defaultState = {\n ...getDefaultTokensState(),\n ...state,\n };\n\n this.initialize();\n this.abortController = new AbortController();\n\n this.messagingSystem = messenger;\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:addDetectedTokens` as const,\n this.addDetectedTokens.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (internalAccount) => {\n this.configure({ selectedAccountId: internalAccount.id });\n if (!isEVMAccount(internalAccount)) {\n return;\n }\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = this.config;\n this.update({\n tokens: allTokens[chainId]?.[internalAccount.address] ?? [],\n ignoredTokens:\n allIgnoredTokens[chainId]?.[internalAccount.address] ?? [],\n detectedTokens:\n allDetectedTokens[chainId]?.[internalAccount.address] ?? [],\n });\n },\n );\n\n this.messagingSystem.subscribe(\n 'NetworkController:networkDidChange',\n ({ providerConfig }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { selectedAccountId } = this.config;\n const selectedInternalAccount = this.messagingSystem.call(\n 'AccountsController:getAccount',\n selectedAccountId,\n );\n\n const { chainId } = providerConfig;\n this.abortController.abort();\n this.abortController = new AbortController();\n this.configure({ chainId });\n if (\n !selectedInternalAccount ||\n !isEVMAccount(selectedInternalAccount)\n ) {\n return;\n }\n this.update({\n tokens: allTokens[chainId]?.[selectedInternalAccount.address] || [],\n ignoredTokens:\n allIgnoredTokens[chainId]?.[selectedInternalAccount.address] || [],\n detectedTokens:\n allDetectedTokens[chainId]?.[selectedInternalAccount.address] || [],\n });\n },\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 * 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, selectedAccountId } = this.config;\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 internalAccount = this.messagingSystem.call(\n 'AccountsController:getAccount',\n selectedAccountId,\n );\n if (!internalAccount || !isEVMAccount(internalAccount)) {\n releaseLock();\n return [];\n }\n\n const accountAddress = interactingAddress || internalAccount.address;\n const isInteractingWithWalletAccount =\n accountAddress === internalAccount.address;\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.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 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<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 = 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({\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\n const internalAccount = this.messagingSystem.call(\n 'AccountsController:getAccount',\n this.config.selectedAccountId,\n );\n if (!internalAccount || !isEVMAccount(internalAccount)) {\n releaseLock();\n return;\n }\n\n // Get existing tokens for the chain + account\n const chainId = detectionDetails?.chainId ?? this.config.chainId;\n const accountAddress =\n detectionDetails?.selectedAddress ?? internalAccount.address;\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 const { chainId: currentChain, selectedAccountId: currentAccountId } =\n this.config;\n\n const currentInternalAccount = this.messagingSystem.call(\n 'AccountsController:getAccount',\n currentAccountId,\n );\n\n if (!currentInternalAccount || !isEVMAccount(currentInternalAccount)) {\n releaseLock();\n return;\n }\n\n newTokens =\n newAllTokens?.[currentChain]?.[currentInternalAccount.address] || [];\n newDetectedTokens =\n newAllDetectedTokens?.[currentChain]?.[\n currentInternalAccount.address\n ] || [];\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) {\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.config.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 if account is an evm account\n const selectedAccount = this.messagingSystem.call(\n 'AccountsController:getAccount',\n this.config.selectedAccountId,\n );\n if (!selectedAccount || !isEVMAccount(selectedAccount)) {\n throw new Error(`Account is not an EVM account`);\n }\n\n // Validate contract\n\n if (await this._detectIsERC721(asset.address, networkClientId)) {\n throw rpcErrors.invalidParams(\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 `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 `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 `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 `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 || selectedAccount.address,\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 const { chainId, selectedAccountId } = this.config;\n const selectedInternalAccount = this.messagingSystem.call(\n 'AccountsController:getAccount',\n selectedAccountId,\n );\n if (!selectedInternalAccount || !isEVMAccount(selectedInternalAccount)) {\n return {\n newAllTokens: allTokens,\n newAllIgnoredTokens: allIgnoredTokens,\n newAllDetectedTokens: allDetectedTokens,\n };\n }\n\n const userAddressToAddTokens =\n interactingAddress ?? selectedInternalAccount.address;\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"],"mappings":"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","names":[]}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// src/NftDetectionController.ts
|
|
2
|
-
import { isEVMAccount } from "@metamask/accounts-controller";
|
|
3
2
|
import {
|
|
4
3
|
fetchWithErrorHandling,
|
|
5
4
|
toChecksumHexAddress,
|
|
@@ -24,15 +23,13 @@ var NftDetectionController = class extends StaticIntervalPollingControllerV1 {
|
|
|
24
23
|
* @param options.onNftsStateChange - Allows subscribing to assets controller state changes.
|
|
25
24
|
* @param options.onPreferencesStateChange - Allows subscribing to preferences controller state changes.
|
|
26
25
|
* @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
|
|
27
|
-
* @param options.onSelectedAccountChange - Allows subscribing to the change of account from the accoutns controller.
|
|
28
26
|
* @param options.getOpenSeaApiKey - Gets the OpenSea API key, if one is set.
|
|
29
27
|
* @param options.addNft - Add an NFT.
|
|
30
28
|
* @param options.getNftApi - Gets the URL to fetch an NFT from OpenSea.
|
|
31
29
|
* @param options.getNftState - Gets the current state of the Assets controller.
|
|
32
30
|
* @param options.disabled - Represents previous value of useNftDetection. Used to detect changes of useNftDetection. Default value is true.
|
|
33
|
-
* @param options.
|
|
31
|
+
* @param options.selectedAddress - Represents current selected address.
|
|
34
32
|
* @param options.getNetworkClientById - Gets the network client by ID, from the NetworkController.
|
|
35
|
-
* @param options.getInternalAccount - Gets the internal account from the AccountsController.
|
|
36
33
|
* @param config - Initial options used to configure this controller.
|
|
37
34
|
* @param state - Initial state to set on this controller.
|
|
38
35
|
*/
|
|
@@ -41,14 +38,12 @@ var NftDetectionController = class extends StaticIntervalPollingControllerV1 {
|
|
|
41
38
|
getNetworkClientById,
|
|
42
39
|
onPreferencesStateChange,
|
|
43
40
|
onNetworkStateChange,
|
|
44
|
-
onSelectedAccountChange,
|
|
45
41
|
getOpenSeaApiKey,
|
|
46
42
|
addNft,
|
|
47
43
|
getNftApi,
|
|
48
44
|
getNftState,
|
|
49
|
-
getInternalAccount,
|
|
50
45
|
disabled: initialDisabled,
|
|
51
|
-
|
|
46
|
+
selectedAddress: initialSelectedAddress
|
|
52
47
|
}, config, state) {
|
|
53
48
|
super(config, state);
|
|
54
49
|
/**
|
|
@@ -67,33 +62,17 @@ var NftDetectionController = class extends StaticIntervalPollingControllerV1 {
|
|
|
67
62
|
this.defaultConfig = {
|
|
68
63
|
interval: DEFAULT_INTERVAL,
|
|
69
64
|
chainId: initialChainId,
|
|
70
|
-
|
|
65
|
+
selectedAddress: initialSelectedAddress,
|
|
71
66
|
disabled: initialDisabled
|
|
72
67
|
};
|
|
73
68
|
this.initialize();
|
|
74
69
|
this.getNftState = getNftState;
|
|
75
70
|
this.getNetworkClientById = getNetworkClientById;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (!
|
|
79
|
-
this.configure({
|
|
80
|
-
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const { selectedAccountId, disabled } = this.config;
|
|
84
|
-
if (!disabled && selectedAccountId !== internalAccount.id) {
|
|
85
|
-
this.configure({ selectedAccountId: internalAccount.id });
|
|
86
|
-
this.start();
|
|
87
|
-
} else {
|
|
88
|
-
this.stop();
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
onPreferencesStateChange(({ useNftDetection }) => {
|
|
92
|
-
const { disabled, selectedAccountId } = this.config;
|
|
93
|
-
const selectedInternalAccount = this.getInternalAccount(selectedAccountId);
|
|
94
|
-
if (!useNftDetection !== disabled) {
|
|
95
|
-
this.configure({ disabled: !useNftDetection });
|
|
96
|
-
if (useNftDetection && isEVMAccount(selectedInternalAccount)) {
|
|
71
|
+
onPreferencesStateChange(({ selectedAddress, useNftDetection }) => {
|
|
72
|
+
const { selectedAddress: previouslySelectedAddress, disabled } = this.config;
|
|
73
|
+
if (selectedAddress !== previouslySelectedAddress || !useNftDetection !== disabled) {
|
|
74
|
+
this.configure({ selectedAddress, disabled: !useNftDetection });
|
|
75
|
+
if (useNftDetection) {
|
|
97
76
|
this.start();
|
|
98
77
|
} else {
|
|
99
78
|
this.stop();
|
|
@@ -187,13 +166,7 @@ var NftDetectionController = class extends StaticIntervalPollingControllerV1 {
|
|
|
187
166
|
async detectNfts({
|
|
188
167
|
networkClientId,
|
|
189
168
|
userAddress
|
|
190
|
-
} = {}) {
|
|
191
|
-
const { selectedAccountId } = this.config;
|
|
192
|
-
const selectedInternalAccount = this.getInternalAccount(selectedAccountId);
|
|
193
|
-
if (!isEVMAccount(selectedInternalAccount)) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
userAddress = userAddress || selectedInternalAccount.address;
|
|
169
|
+
} = { userAddress: this.config.selectedAddress }) {
|
|
197
170
|
if (!this.isMainnet() || this.disabled) {
|
|
198
171
|
return;
|
|
199
172
|
}
|
|
@@ -259,4 +232,4 @@ export {
|
|
|
259
232
|
NftDetectionController,
|
|
260
233
|
NftDetectionController_default
|
|
261
234
|
};
|
|
262
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-ASFD56OL.mjs.map
|