@metamask-previews/assets-controllers 16.0.0-preview.e3b05ea → 17.0.0-preview.7f750b2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/dist/CurrencyRateController.d.ts +22 -38
- package/dist/CurrencyRateController.d.ts.map +1 -1
- package/dist/CurrencyRateController.js +52 -113
- package/dist/CurrencyRateController.js.map +1 -1
- package/dist/TokensController.d.ts.map +1 -1
- package/dist/TokensController.js +24 -22
- package/dist/TokensController.js.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [17.0.0]
|
|
10
|
+
### Changed
|
|
11
|
+
- **BREAKING:** Bump dependency on `@metamask/polling-controller` to ^1.0.0
|
|
12
|
+
- Bump dependency and peer dependency on `@metamask/network-controller` to ^15.1.0
|
|
13
|
+
|
|
9
14
|
## [16.0.0]
|
|
10
15
|
### Added
|
|
11
16
|
- Add way to start and stop different polling sessions for the same network client ID by providing extra scoping data ([#1776](https://github.com/MetaMask/core/pull/1776))
|
|
@@ -334,7 +339,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
334
339
|
### Changed
|
|
335
340
|
- Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/core/pull/845))
|
|
336
341
|
|
|
337
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@
|
|
342
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@17.0.0...HEAD
|
|
343
|
+
[17.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@16.0.0...@metamask/assets-controllers@17.0.0
|
|
338
344
|
[16.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@15.0.0...@metamask/assets-controllers@16.0.0
|
|
339
345
|
[15.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@14.0.0...@metamask/assets-controllers@15.0.0
|
|
340
346
|
[14.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@13.0.0...@metamask/assets-controllers@14.0.0
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
import type { RestrictedControllerMessenger } from '@metamask/base-controller';
|
|
2
|
-
import {
|
|
2
|
+
import type { NetworkClientId, NetworkControllerGetNetworkClientByIdAction } from '@metamask/network-controller';
|
|
3
|
+
import { PollingController } from '@metamask/polling-controller';
|
|
3
4
|
import type { Patch } from 'immer';
|
|
4
5
|
import { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare';
|
|
5
6
|
/**
|
|
6
7
|
* @type CurrencyRateState
|
|
7
|
-
* @property
|
|
8
|
-
* @property
|
|
8
|
+
* @property currencyRates - Object keyed by native currency
|
|
9
|
+
* @property currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch
|
|
10
|
+
* @property currencyRates.conversionRate - Conversion rate from current base asset to the current currency
|
|
9
11
|
* @property currentCurrency - Currently-active ISO 4217 currency code
|
|
10
|
-
* @property nativeCurrency - Symbol for the base asset used for conversion
|
|
11
|
-
* @property pendingCurrentCurrency - The currency being switched to
|
|
12
|
-
* @property pendingNativeCurrency - The base asset currency being switched to
|
|
13
12
|
* @property usdConversionRate - Conversion rate from usd to the current currency
|
|
14
13
|
*/
|
|
15
14
|
export declare type CurrencyRateState = {
|
|
16
|
-
conversionDate: number | null;
|
|
17
|
-
conversionRate: number | null;
|
|
18
15
|
currentCurrency: string;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
currencyRates: Record<string, {
|
|
17
|
+
conversionDate: number | null;
|
|
18
|
+
conversionRate: number | null;
|
|
19
|
+
usdConversionRate: number | null;
|
|
20
|
+
}>;
|
|
23
21
|
};
|
|
24
22
|
declare const name = "CurrencyRateController";
|
|
25
23
|
export declare type CurrencyRateStateChange = {
|
|
@@ -30,16 +28,14 @@ export declare type GetCurrencyRateState = {
|
|
|
30
28
|
type: `${typeof name}:getState`;
|
|
31
29
|
handler: () => CurrencyRateState;
|
|
32
30
|
};
|
|
33
|
-
declare type
|
|
31
|
+
declare type AllowedActions = NetworkControllerGetNetworkClientByIdAction;
|
|
32
|
+
declare type CurrencyRateMessenger = RestrictedControllerMessenger<typeof name, GetCurrencyRateState | AllowedActions, CurrencyRateStateChange, AllowedActions['type'], never>;
|
|
34
33
|
/**
|
|
35
34
|
* Controller that passively polls on a set interval for an exchange rate from the current network
|
|
36
35
|
* asset to the user's preferred currency.
|
|
37
36
|
*/
|
|
38
|
-
export declare class CurrencyRateController extends
|
|
39
|
-
#private;
|
|
37
|
+
export declare class CurrencyRateController extends PollingController<typeof name, CurrencyRateState, CurrencyRateMessenger> {
|
|
40
38
|
private readonly mutex;
|
|
41
|
-
private intervalId?;
|
|
42
|
-
private readonly intervalDelay;
|
|
43
39
|
private readonly fetchExchangeRate;
|
|
44
40
|
private readonly includeUsdRate;
|
|
45
41
|
/**
|
|
@@ -59,20 +55,6 @@ export declare class CurrencyRateController extends BaseControllerV2<typeof name
|
|
|
59
55
|
state?: Partial<CurrencyRateState>;
|
|
60
56
|
fetchExchangeRate?: typeof defaultFetchExchangeRate;
|
|
61
57
|
});
|
|
62
|
-
/**
|
|
63
|
-
* Start polling for the currency rate.
|
|
64
|
-
*/
|
|
65
|
-
start(): Promise<void>;
|
|
66
|
-
/**
|
|
67
|
-
* Stop polling for the currency rate.
|
|
68
|
-
*/
|
|
69
|
-
stop(): void;
|
|
70
|
-
/**
|
|
71
|
-
* Prepare to discard this controller.
|
|
72
|
-
*
|
|
73
|
-
* This stops any active polling.
|
|
74
|
-
*/
|
|
75
|
-
destroy(): void;
|
|
76
58
|
/**
|
|
77
59
|
* Sets a currency to track.
|
|
78
60
|
*
|
|
@@ -80,22 +62,24 @@ export declare class CurrencyRateController extends BaseControllerV2<typeof name
|
|
|
80
62
|
*/
|
|
81
63
|
setCurrentCurrency(currentCurrency: string): Promise<void>;
|
|
82
64
|
/**
|
|
83
|
-
*
|
|
65
|
+
* Updates the exchange rate for the current currency and native currency pair.
|
|
84
66
|
*
|
|
85
|
-
* @param
|
|
67
|
+
* @param nativeCurrency - The ticker symbol for the chain.
|
|
86
68
|
*/
|
|
87
|
-
|
|
88
|
-
private stopPolling;
|
|
69
|
+
updateExchangeRate(nativeCurrency: string): Promise<void>;
|
|
89
70
|
/**
|
|
90
|
-
*
|
|
71
|
+
* Prepare to discard this controller.
|
|
72
|
+
*
|
|
73
|
+
* This stops any active polling.
|
|
91
74
|
*/
|
|
92
|
-
|
|
75
|
+
destroy(): void;
|
|
93
76
|
/**
|
|
94
77
|
* Updates exchange rate for the current currency.
|
|
95
78
|
*
|
|
79
|
+
* @param networkClientId - The network client ID used to get a ticker value.
|
|
96
80
|
* @returns The controller state.
|
|
97
81
|
*/
|
|
98
|
-
|
|
82
|
+
_executePoll(networkClientId: NetworkClientId): Promise<void>;
|
|
99
83
|
}
|
|
100
84
|
export default CurrencyRateController;
|
|
101
85
|
//# sourceMappingURL=CurrencyRateController.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyRateController.d.ts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"CurrencyRateController.d.ts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAK/E,OAAO,KAAK,EACV,eAAe,EACf,2CAA2C,EAC5C,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAEnC,OAAO,EAAE,iBAAiB,IAAI,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAEjF;;;;;;;GAOG;AACH,oBAAY,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,oBAAY,uBAAuB,GAAG;IACpC,IAAI,EAAE,GAAG,OAAO,IAAI,cAAc,CAAC;IACnC,OAAO,EAAE,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC;CACvC,CAAC;AAEF,oBAAY,oBAAoB,GAAG;IACjC,IAAI,EAAE,GAAG,OAAO,IAAI,WAAW,CAAC;IAChC,OAAO,EAAE,MAAM,iBAAiB,CAAC;CAClC,CAAC;AAEF,aAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE,aAAK,qBAAqB,GAAG,6BAA6B,CACxD,OAAO,IAAI,EACX,oBAAoB,GAAG,cAAc,EACrC,uBAAuB,EACvB,cAAc,CAAC,MAAM,CAAC,EACtB,KAAK,CACN,CAAC;AAkBF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,iBAAiB,CAC3D,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC;;;;;;;;;OASG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,SAAS,EACT,KAAK,EACL,iBAA4C,GAC7C,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,iBAAiB,CAAC,EAAE,OAAO,wBAAwB,CAAC;KACrD;IAYD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAgBhD;;;;OAIG;IACG,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgE/D;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,eAAe,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;CAOpE;AAED,eAAe,sBAAsB,CAAC"}
|
|
@@ -8,48 +8,32 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
12
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
13
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
14
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
15
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
16
|
-
};
|
|
17
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
18
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
19
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
20
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
21
|
-
};
|
|
22
|
-
var _CurrencyRateController_enabled;
|
|
23
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
12
|
exports.CurrencyRateController = void 0;
|
|
25
|
-
const base_controller_1 = require("@metamask/base-controller");
|
|
26
13
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
14
|
+
const polling_controller_1 = require("@metamask/polling-controller");
|
|
27
15
|
const async_mutex_1 = require("async-mutex");
|
|
28
16
|
const crypto_compare_1 = require("./crypto-compare");
|
|
29
17
|
const name = 'CurrencyRateController';
|
|
30
18
|
const metadata = {
|
|
31
|
-
conversionDate: { persist: true, anonymous: true },
|
|
32
|
-
conversionRate: { persist: true, anonymous: true },
|
|
33
19
|
currentCurrency: { persist: true, anonymous: true },
|
|
34
|
-
|
|
35
|
-
pendingCurrentCurrency: { persist: false, anonymous: true },
|
|
36
|
-
pendingNativeCurrency: { persist: false, anonymous: true },
|
|
37
|
-
usdConversionRate: { persist: true, anonymous: true },
|
|
20
|
+
currencyRates: { persist: true, anonymous: true },
|
|
38
21
|
};
|
|
39
22
|
const defaultState = {
|
|
40
|
-
conversionDate: 0,
|
|
41
|
-
conversionRate: 0,
|
|
42
23
|
currentCurrency: 'usd',
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
currencyRates: {
|
|
25
|
+
ETH: {
|
|
26
|
+
conversionDate: 0,
|
|
27
|
+
conversionRate: 0,
|
|
28
|
+
usdConversionRate: null,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
47
31
|
};
|
|
48
32
|
/**
|
|
49
33
|
* Controller that passively polls on a set interval for an exchange rate from the current network
|
|
50
34
|
* asset to the user's preferred currency.
|
|
51
35
|
*/
|
|
52
|
-
class CurrencyRateController extends
|
|
36
|
+
class CurrencyRateController extends polling_controller_1.PollingController {
|
|
53
37
|
/**
|
|
54
38
|
* Creates a CurrencyRateController instance.
|
|
55
39
|
*
|
|
@@ -68,39 +52,9 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
|
|
|
68
52
|
state: Object.assign(Object.assign({}, defaultState), state),
|
|
69
53
|
});
|
|
70
54
|
this.mutex = new async_mutex_1.Mutex();
|
|
71
|
-
/**
|
|
72
|
-
* A boolean that controls whether or not network requests can be made by the controller
|
|
73
|
-
*/
|
|
74
|
-
_CurrencyRateController_enabled.set(this, void 0);
|
|
75
55
|
this.includeUsdRate = includeUsdRate;
|
|
76
|
-
this.
|
|
56
|
+
this.setIntervalLength(interval);
|
|
77
57
|
this.fetchExchangeRate = fetchExchangeRate;
|
|
78
|
-
__classPrivateFieldSet(this, _CurrencyRateController_enabled, false, "f");
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Start polling for the currency rate.
|
|
82
|
-
*/
|
|
83
|
-
start() {
|
|
84
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
-
__classPrivateFieldSet(this, _CurrencyRateController_enabled, true, "f");
|
|
86
|
-
yield this.startPolling();
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Stop polling for the currency rate.
|
|
91
|
-
*/
|
|
92
|
-
stop() {
|
|
93
|
-
__classPrivateFieldSet(this, _CurrencyRateController_enabled, false, "f");
|
|
94
|
-
this.stopPolling();
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Prepare to discard this controller.
|
|
98
|
-
*
|
|
99
|
-
* This stops any active polling.
|
|
100
|
-
*/
|
|
101
|
-
destroy() {
|
|
102
|
-
super.destroy();
|
|
103
|
-
this.stopPolling();
|
|
104
58
|
}
|
|
105
59
|
/**
|
|
106
60
|
* Sets a currency to track.
|
|
@@ -109,61 +63,31 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
|
|
|
109
63
|
*/
|
|
110
64
|
setCurrentCurrency(currentCurrency) {
|
|
111
65
|
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
-
this.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
setNativeCurrency(symbol) {
|
|
124
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
-
this.update((state) => {
|
|
126
|
-
state.pendingNativeCurrency = symbol;
|
|
127
|
-
});
|
|
128
|
-
yield this.updateExchangeRate();
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
stopPolling() {
|
|
132
|
-
if (this.intervalId) {
|
|
133
|
-
clearInterval(this.intervalId);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Starts a new polling interval.
|
|
138
|
-
*/
|
|
139
|
-
startPolling() {
|
|
140
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
-
this.stopPolling();
|
|
142
|
-
// TODO: Expose polling currency rate update errors
|
|
143
|
-
yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { return yield this.updateExchangeRate(); }));
|
|
144
|
-
this.intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
145
|
-
yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { return yield this.updateExchangeRate(); }));
|
|
146
|
-
}), this.intervalDelay);
|
|
66
|
+
const releaseLock = yield this.mutex.acquire();
|
|
67
|
+
const nativeCurrencies = Object.keys(this.state.currencyRates);
|
|
68
|
+
try {
|
|
69
|
+
this.update(() => {
|
|
70
|
+
return Object.assign(Object.assign({}, defaultState), { currentCurrency });
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
releaseLock();
|
|
75
|
+
}
|
|
76
|
+
nativeCurrencies.forEach(this.updateExchangeRate.bind(this));
|
|
147
77
|
});
|
|
148
78
|
}
|
|
149
79
|
/**
|
|
150
|
-
* Updates exchange rate for the current currency.
|
|
80
|
+
* Updates the exchange rate for the current currency and native currency pair.
|
|
151
81
|
*
|
|
152
|
-
* @
|
|
82
|
+
* @param nativeCurrency - The ticker symbol for the chain.
|
|
153
83
|
*/
|
|
154
|
-
updateExchangeRate() {
|
|
84
|
+
updateExchangeRate(nativeCurrency) {
|
|
155
85
|
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
-
if (!__classPrivateFieldGet(this, _CurrencyRateController_enabled, "f")) {
|
|
157
|
-
console.info('[CurrencyRateController] Not updating exchange rate since network requests have been disabled');
|
|
158
|
-
return this.state;
|
|
159
|
-
}
|
|
160
86
|
const releaseLock = yield this.mutex.acquire();
|
|
161
|
-
const { currentCurrency
|
|
87
|
+
const { currentCurrency, currencyRates } = this.state;
|
|
162
88
|
let conversionDate = null;
|
|
163
89
|
let conversionRate = null;
|
|
164
90
|
let usdConversionRate = null;
|
|
165
|
-
const currentCurrency = pendingCurrentCurrency !== null && pendingCurrentCurrency !== void 0 ? pendingCurrentCurrency : stateCurrentCurrency;
|
|
166
|
-
const nativeCurrency = pendingNativeCurrency !== null && pendingNativeCurrency !== void 0 ? pendingNativeCurrency : stateNativeCurrency;
|
|
167
91
|
// For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.
|
|
168
92
|
const nativeCurrencyForExchangeRate = Object.values(controller_utils_1.TESTNET_TICKER_SYMBOLS).includes(nativeCurrency)
|
|
169
93
|
? controller_utils_1.FALL_BACK_VS_CURRENCY // ETH
|
|
@@ -192,16 +116,12 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
|
|
|
192
116
|
try {
|
|
193
117
|
this.update(() => {
|
|
194
118
|
return {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
nativeCurrency,
|
|
119
|
+
currencyRates: Object.assign(Object.assign({}, currencyRates), { [nativeCurrency]: {
|
|
120
|
+
conversionDate,
|
|
121
|
+
conversionRate,
|
|
122
|
+
usdConversionRate,
|
|
123
|
+
} }),
|
|
201
124
|
currentCurrency,
|
|
202
|
-
pendingCurrentCurrency: null,
|
|
203
|
-
pendingNativeCurrency: null,
|
|
204
|
-
usdConversionRate,
|
|
205
125
|
};
|
|
206
126
|
});
|
|
207
127
|
}
|
|
@@ -209,11 +129,30 @@ class CurrencyRateController extends base_controller_1.BaseControllerV2 {
|
|
|
209
129
|
releaseLock();
|
|
210
130
|
}
|
|
211
131
|
}
|
|
212
|
-
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Prepare to discard this controller.
|
|
136
|
+
*
|
|
137
|
+
* This stops any active polling.
|
|
138
|
+
*/
|
|
139
|
+
destroy() {
|
|
140
|
+
super.destroy();
|
|
141
|
+
this.stopAllPolling();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Updates exchange rate for the current currency.
|
|
145
|
+
*
|
|
146
|
+
* @param networkClientId - The network client ID used to get a ticker value.
|
|
147
|
+
* @returns The controller state.
|
|
148
|
+
*/
|
|
149
|
+
_executePoll(networkClientId) {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
const networkClient = this.messagingSystem.call('NetworkController:getNetworkClientById', networkClientId);
|
|
152
|
+
yield this.updateExchangeRate(networkClient.configuration.ticker);
|
|
213
153
|
});
|
|
214
154
|
}
|
|
215
155
|
}
|
|
216
156
|
exports.CurrencyRateController = CurrencyRateController;
|
|
217
|
-
_CurrencyRateController_enabled = new WeakMap();
|
|
218
157
|
exports.default = CurrencyRateController;
|
|
219
158
|
//# sourceMappingURL=CurrencyRateController.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyRateController.js","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AACA,+DAA6D;AAC7D,iEAIoC;AACpC,6CAAoC;AAGpC,qDAAiF;AAsBjF,MAAM,IAAI,GAAG,wBAAwB,CAAC;AAoBtC,MAAM,QAAQ,GAAG;IACf,cAAc,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;IAClD,cAAc,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;IAClD,eAAe,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;IACnD,cAAc,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;IAClD,sBAAsB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;IAC3D,qBAAqB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;IAC1D,iBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;CACtD,CAAC;AAEF,MAAM,YAAY,GAAG;IACnB,cAAc,EAAE,CAAC;IACjB,cAAc,EAAE,CAAC;IACjB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,sBAAsB,EAAE,IAAI;IAC5B,qBAAqB,EAAE,IAAI;IAC3B,iBAAiB,EAAE,IAAI;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAa,sBAAuB,SAAQ,kCAI3C;IAgBC;;;;;;;;;OASG;IACH,YAAY,EACV,cAAc,GAAG,KAAK,EACtB,QAAQ,GAAG,MAAM,EACjB,SAAS,EACT,KAAK,EACL,iBAAiB,GAAG,kCAAwB,GAO7C;QACC,KAAK,CAAC;YACJ,IAAI;YACJ,QAAQ;YACR,SAAS;YACT,KAAK,kCAAO,YAAY,GAAK,KAAK,CAAE;SACrC,CAAC,CAAC;QA3CY,UAAK,GAAG,IAAI,mBAAK,EAAE,CAAC;QAUrC;;WAEG;QACH,kDAAS;QA+BP,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,uBAAA,IAAI,mCAAY,KAAK,MAAA,CAAC;IACxB,CAAC;IAED;;OAEG;IACG,KAAK;;YACT,uBAAA,IAAI,mCAAY,IAAI,MAAA,CAAC;YAErB,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC5B,CAAC;KAAA;IAED;;OAEG;IACH,IAAI;QACF,uBAAA,IAAI,mCAAY,KAAK,MAAA,CAAC;QAEtB,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACM,OAAO;QACd,KAAK,CAAC,OAAO,EAAE,CAAC;QAChB,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACG,kBAAkB,CAAC,eAAuB;;YAC9C,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,KAAK,CAAC,sBAAsB,GAAG,eAAe,CAAC;YACjD,CAAC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAClC,CAAC;KAAA;IAED;;;;OAIG;IACG,iBAAiB,CAAC,MAAc;;YACpC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,KAAK,CAAC,qBAAqB,GAAG,MAAM,CAAC;YACvC,CAAC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAClC,CAAC;KAAA;IAEO,WAAW;QACjB,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SAChC;IACH,CAAC;IAED;;OAEG;IACW,YAAY;;YACxB,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,mDAAmD;YAEnD,MAAM,IAAA,gCAAa,EAAC,GAAS,EAAE,gDAAC,OAAA,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA,GAAA,CAAC,CAAC;YAEjE,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAS,EAAE;gBACvC,MAAM,IAAA,gCAAa,EAAC,GAAS,EAAE,gDAAC,OAAA,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA,GAAA,CAAC,CAAC;YACnE,CAAC,CAAA,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACzB,CAAC;KAAA;IAED;;;;OAIG;IACG,kBAAkB;;YACtB,IAAI,CAAC,uBAAA,IAAI,uCAAS,EAAE;gBAClB,OAAO,CAAC,IAAI,CACV,+FAA+F,CAChG,CAAC;gBACF,OAAO,IAAI,CAAC,KAAK,CAAC;aACnB;YACD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/C,MAAM,EACJ,eAAe,EAAE,oBAAoB,EACrC,cAAc,EAAE,mBAAmB,EACnC,sBAAsB,EACtB,qBAAqB,GACtB,GAAG,IAAI,CAAC,KAAK,CAAC;YAEf,IAAI,cAAc,GAAkB,IAAI,CAAC;YACzC,IAAI,cAAc,GAAkB,IAAI,CAAC;YACzC,IAAI,iBAAiB,GAAkB,IAAI,CAAC;YAC5C,MAAM,eAAe,GAAG,sBAAsB,aAAtB,sBAAsB,cAAtB,sBAAsB,GAAI,oBAAoB,CAAC;YACvE,MAAM,cAAc,GAAG,qBAAqB,aAArB,qBAAqB,cAArB,qBAAqB,GAAI,mBAAmB,CAAC;YAEpE,wFAAwF;YACxF,MAAM,6BAA6B,GAAG,MAAM,CAAC,MAAM,CACjD,yCAAsB,CACvB,CAAC,QAAQ,CAAC,cAAc,CAAC;gBACxB,CAAC,CAAC,wCAAqB,CAAC,MAAM;gBAC9B,CAAC,CAAC,cAAc,CAAC;YAEnB,IAAI;gBACF,IACE,eAAe;oBACf,cAAc;oBACd,mEAAmE;oBACnE,iEAAiE;oBACjE,oCAAoC;oBACpC,eAAe,KAAK,EAAE;oBACtB,cAAc,KAAK,EAAE,EACrB;oBACA,MAAM,yBAAyB,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAC5D,eAAe,EACf,6BAA6B,EAC7B,IAAI,CAAC,cAAc,CACpB,CAAC;oBAEF,cAAc,GAAG,yBAAyB,CAAC,cAAc,CAAC;oBAC1D,iBAAiB,GAAG,yBAAyB,CAAC,iBAAiB,CAAC;oBAChE,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;iBACpC;aACF;YAAC,OAAO,KAAK,EAAE;gBACd,IACE,CAAC,CACC,KAAK,YAAY,KAAK;oBACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,0CAA0C,CAAC,CACnE,EACD;oBACA,MAAM,KAAK,CAAC;iBACb;aACF;oBAAS;gBACR,IAAI;oBACF,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;wBACf,OAAO;4BACL,cAAc;4BACd,cAAc;4BACd,0EAA0E;4BAC1E,oFAAoF;4BACpF,uFAAuF;4BACvF,cAAc;4BACd,eAAe;4BACf,sBAAsB,EAAE,IAAI;4BAC5B,qBAAqB,EAAE,IAAI;4BAC3B,iBAAiB;yBAClB,CAAC;oBACJ,CAAC,CAAC,CAAC;iBACJ;wBAAS;oBACR,WAAW,EAAE,CAAC;iBACf;aACF;YACD,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;KAAA;CACF;AAnND,wDAmNC;;AAED,kBAAe,sBAAsB,CAAC","sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport { BaseControllerV2 } from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n safelyExecute,\n} from '@metamask/controller-utils';\nimport { Mutex } from 'async-mutex';\nimport type { Patch } from 'immer';\n\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare';\n\n/**\n * @type CurrencyRateState\n * @property conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property nativeCurrency - Symbol for the base asset used for conversion\n * @property pendingCurrentCurrency - The currency being switched to\n * @property pendingNativeCurrency - The base asset currency being switched to\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n conversionDate: number | null;\n conversionRate: number | null;\n currentCurrency: string;\n nativeCurrency: string;\n pendingCurrentCurrency: string | null;\n pendingNativeCurrency: string | null;\n usdConversionRate: number | null;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = {\n type: `${typeof name}:stateChange`;\n payload: [CurrencyRateState, Patch[]];\n};\n\nexport type GetCurrencyRateState = {\n type: `${typeof name}:getState`;\n handler: () => CurrencyRateState;\n};\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n GetCurrencyRateState,\n CurrencyRateStateChange,\n never,\n never\n>;\n\nconst metadata = {\n conversionDate: { persist: true, anonymous: true },\n conversionRate: { persist: true, anonymous: true },\n currentCurrency: { persist: true, anonymous: true },\n nativeCurrency: { persist: true, anonymous: true },\n pendingCurrentCurrency: { persist: false, anonymous: true },\n pendingNativeCurrency: { persist: false, anonymous: true },\n usdConversionRate: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n conversionDate: 0,\n conversionRate: 0,\n currentCurrency: 'usd',\n nativeCurrency: 'ETH',\n pendingCurrentCurrency: null,\n pendingNativeCurrency: null,\n usdConversionRate: null,\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends BaseControllerV2<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private intervalId?: ReturnType<typeof setTimeout>;\n\n private readonly intervalDelay;\n\n private readonly fetchExchangeRate;\n\n private readonly includeUsdRate;\n\n /**\n * A boolean that controls whether or not network requests can be made by the controller\n */\n #enabled;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messaging system.\n * @param options.state - Initial state to set on this controller.\n * @param options.fetchExchangeRate - Fetches the exchange rate from an external API. This option is primarily meant for use in unit tests.\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n messenger,\n state,\n fetchExchangeRate = defaultFetchExchangeRate,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n fetchExchangeRate?: typeof defaultFetchExchangeRate;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.intervalDelay = interval;\n this.fetchExchangeRate = fetchExchangeRate;\n this.#enabled = false;\n }\n\n /**\n * Start polling for the currency rate.\n */\n async start() {\n this.#enabled = true;\n\n await this.startPolling();\n }\n\n /**\n * Stop polling for the currency rate.\n */\n stop() {\n this.#enabled = false;\n\n this.stopPolling();\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopPolling();\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n this.update((state) => {\n state.pendingCurrentCurrency = currentCurrency;\n });\n await this.updateExchangeRate();\n }\n\n /**\n * Sets a new native currency.\n *\n * @param symbol - Symbol for the base asset.\n */\n async setNativeCurrency(symbol: string) {\n this.update((state) => {\n state.pendingNativeCurrency = symbol;\n });\n await this.updateExchangeRate();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n private async startPolling(): Promise<void> {\n this.stopPolling();\n // TODO: Expose polling currency rate update errors\n\n await safelyExecute(async () => await this.updateExchangeRate());\n\n this.intervalId = setInterval(async () => {\n await safelyExecute(async () => await this.updateExchangeRate());\n }, this.intervalDelay);\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @returns The controller state.\n */\n async updateExchangeRate(): Promise<CurrencyRateState | void> {\n if (!this.#enabled) {\n console.info(\n '[CurrencyRateController] Not updating exchange rate since network requests have been disabled',\n );\n return this.state;\n }\n const releaseLock = await this.mutex.acquire();\n const {\n currentCurrency: stateCurrentCurrency,\n nativeCurrency: stateNativeCurrency,\n pendingCurrentCurrency,\n pendingNativeCurrency,\n } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n const currentCurrency = pendingCurrentCurrency ?? stateCurrentCurrency;\n const nativeCurrency = pendingNativeCurrency ?? stateNativeCurrency;\n\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n const nativeCurrencyForExchangeRate = Object.values(\n TESTNET_TICKER_SYMBOLS,\n ).includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY // ETH\n : nativeCurrency;\n\n try {\n if (\n currentCurrency &&\n nativeCurrency &&\n // if either currency is an empty string we can skip the comparison\n // because it will result in an error from the api and ultimately\n // a null conversionRate either way.\n currentCurrency !== '' &&\n nativeCurrency !== ''\n ) {\n const fetchExchangeRateResponse = await this.fetchExchangeRate(\n currentCurrency,\n nativeCurrencyForExchangeRate,\n this.includeUsdRate,\n );\n\n conversionRate = fetchExchangeRateResponse.conversionRate;\n usdConversionRate = fetchExchangeRateResponse.usdConversionRate;\n conversionDate = Date.now() / 1000;\n }\n } catch (error) {\n if (\n !(\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n )\n ) {\n throw error;\n }\n } finally {\n try {\n this.update(() => {\n return {\n conversionDate,\n conversionRate,\n // we currently allow and handle an empty string as a valid nativeCurrency\n // in cases where a user has not entered a native ticker symbol for a custom network\n // currentCurrency is not from user input but this protects us from unexpected changes.\n nativeCurrency,\n currentCurrency,\n pendingCurrentCurrency: null,\n pendingNativeCurrency: null,\n usdConversionRate,\n };\n });\n } finally {\n releaseLock();\n }\n }\n return this.state;\n }\n}\n\nexport default CurrencyRateController;\n"]}
|
|
1
|
+
{"version":3,"file":"CurrencyRateController.js","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n} from '@metamask/network-controller';\nimport { PollingController } from '@metamask/polling-controller';\nimport { Mutex } from 'async-mutex';\nimport type { Patch } from 'immer';\n\nimport { fetchExchangeRate as defaultFetchExchangeRate } from './crypto-compare';\n\n/**\n * @type CurrencyRateState\n * @property currencyRates - Object keyed by native currency\n * @property currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n * @property currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n * @property currentCurrency - Currently-active ISO 4217 currency code\n * @property usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = {\n type: `${typeof name}:stateChange`;\n payload: [CurrencyRateState, Patch[]];\n};\n\nexport type GetCurrencyRateState = {\n type: `${typeof name}:getState`;\n handler: () => CurrencyRateState;\n};\n\ntype AllowedActions = NetworkControllerGetNetworkClientByIdAction;\n\ntype CurrencyRateMessenger = RestrictedControllerMessenger<\n typeof name,\n GetCurrencyRateState | AllowedActions,\n CurrencyRateStateChange,\n AllowedActions['type'],\n never\n>;\n\nconst metadata = {\n currentCurrency: { persist: true, anonymous: true },\n currencyRates: { persist: true, anonymous: true },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends PollingController<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly fetchExchangeRate;\n\n private readonly includeUsdRate;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messaging system.\n * @param options.state - Initial state to set on this controller.\n * @param options.fetchExchangeRate - Fetches the exchange rate from an external API. This option is primarily meant for use in unit tests.\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n messenger,\n state,\n fetchExchangeRate = defaultFetchExchangeRate,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n fetchExchangeRate?: typeof defaultFetchExchangeRate;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.setIntervalLength(interval);\n this.fetchExchangeRate = fetchExchangeRate;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n nativeCurrencies.forEach(this.updateExchangeRate.bind(this));\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pair.\n *\n * @param nativeCurrency - The ticker symbol for the chain.\n */\n async updateExchangeRate(nativeCurrency: string): Promise<void> {\n const releaseLock = await this.mutex.acquire();\n const { currentCurrency, currencyRates } = this.state;\n\n let conversionDate: number | null = null;\n let conversionRate: number | null = null;\n let usdConversionRate: number | null = null;\n\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n const nativeCurrencyForExchangeRate = Object.values(\n TESTNET_TICKER_SYMBOLS,\n ).includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY // ETH\n : nativeCurrency;\n\n try {\n if (\n currentCurrency &&\n nativeCurrency &&\n // if either currency is an empty string we can skip the comparison\n // because it will result in an error from the api and ultimately\n // a null conversionRate either way.\n currentCurrency !== '' &&\n nativeCurrency !== ''\n ) {\n const fetchExchangeRateResponse = await this.fetchExchangeRate(\n currentCurrency,\n nativeCurrencyForExchangeRate,\n this.includeUsdRate,\n );\n conversionRate = fetchExchangeRateResponse.conversionRate;\n usdConversionRate = fetchExchangeRateResponse.usdConversionRate;\n conversionDate = Date.now() / 1000;\n }\n } catch (error) {\n if (\n !(\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n )\n ) {\n throw error;\n }\n } finally {\n try {\n this.update(() => {\n return {\n currencyRates: {\n ...currencyRates,\n [nativeCurrency]: {\n conversionDate,\n conversionRate,\n usdConversionRate,\n },\n },\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param networkClientId - The network client ID used to get a ticker value.\n * @returns The controller state.\n */\n async _executePoll(networkClientId: NetworkClientId): Promise<void> {\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n await this.updateExchangeRate(networkClient.configuration.ticker);\n }\n}\n\nexport default CurrencyRateController;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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"}
|
package/dist/TokensController.js
CHANGED
|
@@ -171,9 +171,8 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
171
171
|
aggregators: (0, assetsUtil_1.formatAggregatorNames)((tokenMetadata === null || tokenMetadata === void 0 ? void 0 : tokenMetadata.aggregators) || []),
|
|
172
172
|
name,
|
|
173
173
|
};
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
176
|
-
const previousIndex = newTokens.indexOf(previousEntry);
|
|
174
|
+
const previousIndex = newTokens.findIndex((token) => token.address.toLowerCase() === address.toLowerCase());
|
|
175
|
+
if (previousIndex !== -1) {
|
|
177
176
|
newTokens[previousIndex] = newEntry;
|
|
178
177
|
}
|
|
179
178
|
else {
|
|
@@ -305,14 +304,20 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
305
304
|
* @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.
|
|
306
305
|
*/
|
|
307
306
|
addDetectedTokens(incomingDetectedTokens, detectionDetails) {
|
|
308
|
-
var _a;
|
|
307
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
309
308
|
return __awaiter(this, void 0, void 0, function* () {
|
|
310
309
|
const releaseLock = yield this.mutex.acquire();
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
|
|
310
|
+
// Get existing tokens for the chain + account
|
|
311
|
+
const chainId = (_a = detectionDetails === null || detectionDetails === void 0 ? void 0 : detectionDetails.chainId) !== null && _a !== void 0 ? _a : this.config.chainId;
|
|
312
|
+
const accountAddress = (_b = detectionDetails === null || detectionDetails === void 0 ? void 0 : detectionDetails.selectedAddress) !== null && _b !== void 0 ? _b : this.config.selectedAddress;
|
|
313
|
+
const { allTokens, allDetectedTokens, allIgnoredTokens } = this.state;
|
|
314
|
+
let newTokens = [...((_d = (_c = allTokens === null || allTokens === void 0 ? void 0 : allTokens[chainId]) === null || _c === void 0 ? void 0 : _c[accountAddress]) !== null && _d !== void 0 ? _d : [])];
|
|
315
|
+
let newDetectedTokens = [
|
|
316
|
+
...((_f = (_e = allDetectedTokens === null || allDetectedTokens === void 0 ? void 0 : allDetectedTokens[chainId]) === null || _e === void 0 ? void 0 : _e[accountAddress]) !== null && _f !== void 0 ? _f : []),
|
|
317
|
+
];
|
|
314
318
|
try {
|
|
315
319
|
incomingDetectedTokens.forEach((tokenToAdd) => {
|
|
320
|
+
var _a, _b, _c;
|
|
316
321
|
const { address, symbol, decimals, image, aggregators, isERC721, name, } = tokenToAdd;
|
|
317
322
|
const checksumAddress = (0, controller_utils_1.toChecksumHexAddress)(address);
|
|
318
323
|
const newEntry = {
|
|
@@ -324,19 +329,17 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
324
329
|
aggregators,
|
|
325
330
|
name,
|
|
326
331
|
};
|
|
327
|
-
const
|
|
328
|
-
if (
|
|
332
|
+
const previousImportedIndex = newTokens.findIndex((token) => token.address.toLowerCase() === checksumAddress.toLowerCase());
|
|
333
|
+
if (previousImportedIndex !== -1) {
|
|
329
334
|
// Update existing data of imported token
|
|
330
|
-
const previousImportedIndex = newTokens.indexOf(previousImportedEntry);
|
|
331
335
|
newTokens[previousImportedIndex] = newEntry;
|
|
332
336
|
}
|
|
333
337
|
else {
|
|
334
|
-
const ignoredTokenIndex =
|
|
338
|
+
const ignoredTokenIndex = (_c = (_b = (_a = allIgnoredTokens === null || allIgnoredTokens === void 0 ? void 0 : allIgnoredTokens[chainId]) === null || _a === void 0 ? void 0 : _a[accountAddress]) === null || _b === void 0 ? void 0 : _b.indexOf(address)) !== null && _c !== void 0 ? _c : -1;
|
|
335
339
|
if (ignoredTokenIndex === -1) {
|
|
336
340
|
// Add detected token
|
|
337
|
-
const
|
|
338
|
-
if (
|
|
339
|
-
const previousDetectedIndex = newDetectedTokens.indexOf(previousDetectedEntry);
|
|
341
|
+
const previousDetectedIndex = newDetectedTokens.findIndex((token) => token.address.toLowerCase() === checksumAddress.toLowerCase());
|
|
342
|
+
if (previousDetectedIndex !== -1) {
|
|
340
343
|
newDetectedTokens[previousDetectedIndex] = newEntry;
|
|
341
344
|
}
|
|
342
345
|
else {
|
|
@@ -345,19 +348,18 @@ class TokensController extends base_controller_1.BaseController {
|
|
|
345
348
|
}
|
|
346
349
|
}
|
|
347
350
|
});
|
|
348
|
-
const { selectedAddress: interactingAddress, chainId: interactingChainId, } = detectionDetails || {};
|
|
349
351
|
const { newAllTokens, newAllDetectedTokens } = this._getNewAllTokensState({
|
|
350
352
|
newTokens,
|
|
351
353
|
newDetectedTokens,
|
|
352
|
-
interactingAddress,
|
|
353
|
-
interactingChainId,
|
|
354
|
+
interactingAddress: accountAddress,
|
|
355
|
+
interactingChainId: chainId,
|
|
354
356
|
});
|
|
355
|
-
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
|
|
357
|
+
// We may be detecting tokens on a different chain/account pair than are currently configured.
|
|
358
|
+
// Re-point `tokens` and `detectedTokens` to keep them referencing the current chain/account.
|
|
359
|
+
const { chainId: currentChain, selectedAddress: currentAddress } = this.config;
|
|
360
|
+
newTokens = ((_g = newAllTokens === null || newAllTokens === void 0 ? void 0 : newAllTokens[currentChain]) === null || _g === void 0 ? void 0 : _g[currentAddress]) || [];
|
|
359
361
|
newDetectedTokens =
|
|
360
|
-
((
|
|
362
|
+
((_h = newAllDetectedTokens === null || newAllDetectedTokens === void 0 ? void 0 : newAllDetectedTokens[currentChain]) === null || _h === void 0 ? void 0 : _h[currentAddress]) || [];
|
|
361
363
|
this.update({
|
|
362
364
|
tokens: newTokens,
|
|
363
365
|
allTokens: newAllTokens,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokensController.js","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wDAAoD;AACpD,wDAAwD;AAOxD,+DAA2D;AAC3D,oFAAuD;AACvD,iEAMoC;AACpC,mEAAwD;AAQxD,6CAAoC;AACpC,mCAAsC;AACtC,+BAAoC;AAGpC,6CAIsB;AACtB,mDAGyB;AA0DzB;;GAEG;AACH,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAkB1C;;GAEG;AACH,MAAa,gBAAiB,SAAQ,gCAGrC;IAgDC;;;;;;;;;;;;;OAaG;IACH,YAAY,EACV,OAAO,EAAE,cAAc,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,MAAM,EACN,KAAK,EACL,SAAS,GAiBV;QACC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAxFN,UAAK,GAAG,IAAI,mBAAK,EAAE,CAAC;QAiCrC;;WAEG;QACH,QAAG,GAAG,IAAI,qBAAY,EAAE,CAAC;QAEzB;;WAEG;QACM,SAAI,GAAG,kBAAkB,CAAC;QAiDjC,IAAI,CAAC,aAAa,mBAChB,eAAe,EAAE,EAAE,EACnB,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,SAAS,IAChB,MAAM,CACV,CAAC;QAEF,IAAI,CAAC,YAAY,mBACf,MAAM,EAAE,EAAE,EACV,aAAa,EAAE,EAAE,EACjB,cAAc,EAAE,EAAE,EAClB,SAAS,EAAE,EAAE,EACb,gBAAgB,EAAE,EAAE,EACpB,iBAAiB,EAAE,EAAE,IAClB,KAAK,CACT,CAAC;QAEF,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC7C,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,oBAAoB,GAAG,oBAAoB,CAAC;QAEjD,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QAEjC,wBAAwB,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE;;YAC/C,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACtE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YAChC,IAAI,CAAC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC;gBACV,MAAM,EAAE,CAAA,MAAA,SAAS,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACnD,aAAa,EAAE,CAAA,MAAA,gBAAgB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACjE,cAAc,EAAE,CAAA,MAAA,iBAAiB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;aACpE,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,oBAAoB,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE;;YAC1C,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACtE,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YACxC,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC;YACnC,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;YAC7C,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC;gBACV,MAAM,EAAE,CAAA,MAAA,SAAS,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACnD,aAAa,EAAE,CAAA,MAAA,gBAAgB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACjE,cAAc,EAAE,CAAA,MAAA,iBAAiB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;aACpE,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,sBAAsB,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;YACvC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBACpC,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;aAC/C;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IA3ID;;;;;OAKG;IACW,kBAAkB,CAC9B,YAAoB;;YAEpB,IAAI;gBACF,MAAM,KAAK,GAAG,MAAM,IAAA,kCAAkB,EACpC,IAAI,CAAC,MAAM,CAAC,OAAO,EACnB,YAAY,EACZ,IAAI,CAAC,eAAe,CAAC,MAAM,CAC5B,CAAC;gBACF,OAAO,KAAK,CAAC;aACd;YAAC,OAAO,KAAK,EAAE;gBACd,IACE,KAAK,YAAY,KAAK;oBACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,+CAA+B,CAAC,EACvD;oBACA,OAAO,SAAS,CAAC;iBAClB;gBACD,MAAM,KAAK,CAAC;aACb;QACH,CAAC;KAAA;IAoHD;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,EACb,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,kBAAkB,EAClB,eAAe,GAShB;;;YACC,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YACjD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/C,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACtE,IAAI,cAAc,GAAG,OAAO,CAAC;YAC7B,IAAI,eAAe,EAAE;gBACnB,cAAc;oBACZ,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC;aACpE;YAED,MAAM,cAAc,GAAG,kBAAkB,IAAI,eAAe,CAAC;YAC7D,MAAM,8BAA8B,GAAG,cAAc,KAAK,eAAe,CAAC;YAE1E,IAAI;gBACF,OAAO,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;gBACxC,MAAM,MAAM,GAAG,CAAA,MAAA,SAAS,CAAC,cAAc,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBACjE,MAAM,aAAa,GACjB,CAAA,MAAA,gBAAgB,CAAC,cAAc,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBAC3D,MAAM,cAAc,GAClB,CAAA,MAAA,iBAAiB,CAAC,cAAc,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBAC5D,MAAM,SAAS,GAAY,CAAC,GAAG,MAAM,CAAC,CAAC;gBACvC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;oBAClD,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,eAAe,CAAC;oBAC9C,gEAAgE;oBAChE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;iBACjC,CAAC,CAAC;gBACH,8EAA8E;gBAC9E,IAAI,CAAC,eAAe,IAAI,cAAc,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;oBAC9D,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;iBACH;gBACD,MAAM,QAAQ,GAAU;oBACtB,OAAO;oBACP,MAAM;oBACN,QAAQ;oBACR,KAAK,EACH,KAAK;wBACL,IAAA,mCAAsB,EAAC;4BACrB,OAAO,EAAE,cAAc;4BACvB,YAAY,EAAE,OAAO;yBACtB,CAAC;oBACJ,QAAQ;oBACR,WAAW,EAAE,IAAA,kCAAqB,EAAC,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,WAAW,KAAI,EAAE,CAAC;oBACpE,IAAI;iBACL,CAAC;gBACF,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAClC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACjE,CAAC;gBACF,IAAI,aAAa,EAAE;oBACjB,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;oBACvD,SAAS,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;iBACrC;qBAAM;oBACL,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;iBAC1B;gBAED,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAC3C,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACvE,CAAC;gBACF,MAAM,iBAAiB,GAAG,cAAc,CAAC,MAAM,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACjE,CAAC;gBAEF,MAAM,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,GAC/D,IAAI,CAAC,qBAAqB,CAAC;oBACzB,SAAS;oBACT,gBAAgB;oBAChB,iBAAiB;oBACjB,kBAAkB,EAAE,cAAc;oBAClC,kBAAkB,EAAE,cAAc;iBACnC,CAAC,CAAC;gBAEL,IAAI,QAAQ,GAAyB;oBACnC,SAAS,EAAE,YAAY;oBACvB,gBAAgB,EAAE,mBAAmB;oBACrC,iBAAiB,EAAE,oBAAoB;iBACxC,CAAC;gBAEF,qFAAqF;gBACrF,IAAI,8BAA8B,EAAE;oBAClC,QAAQ,mCACH,QAAQ,KACX,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,gBAAgB,EAC/B,cAAc,EAAE,iBAAiB,GAClC,CAAC;iBACH;gBAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACtB,OAAO,SAAS,CAAC;aAClB;oBAAS;gBACR,WAAW,EAAE,CAAC;aACf;;KACF;IAED;;;;;OAKG;IACG,SAAS,CAAC,cAAuB,EAAE,eAAiC;;YACxE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/C,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAC7D,MAAM,iBAAiB,GAA4B,EAAE,CAAC;YACtD,uCAAuC;YACvC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;gBACrD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;gBAClC,OAAO,MAAM,CAAC;YAChB,CAAC,EAAE,EAAkC,CAAC,CAAC;YACvC,IAAI;gBACF,cAAc,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;oBACpC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,GAC3D,UAAU,CAAC;oBACb,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;oBACtD,MAAM,cAAc,GAAU;wBAC5B,OAAO,EAAE,eAAe;wBACxB,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,WAAW;wBACX,IAAI;qBACL,CAAC;oBACF,YAAY,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC;oBACvC,iBAAiB,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC;oBAChD,OAAO,cAAc,CAAC;gBACxB,CAAC,CAAC,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;gBAE9C,MAAM,iBAAiB,GAAG,cAAc,CAAC,MAAM,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAC3D,CAAC;gBACF,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAC3C,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAC5D,CAAC;gBAEF,IAAI,kBAAkB,CAAC;gBACvB,IAAI,eAAe,EAAE;oBACnB,kBAAkB;wBAChB,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC;iBACpE;gBAED,MAAM,EAAE,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,GAC/D,IAAI,CAAC,qBAAqB,CAAC;oBACzB,SAAS;oBACT,iBAAiB;oBACjB,gBAAgB;oBAChB,kBAAkB;iBACnB,CAAC,CAAC;gBAEL,IAAI,CAAC,MAAM,CAAC;oBACV,MAAM,EAAE,SAAS;oBACjB,SAAS,EAAE,YAAY;oBACvB,cAAc,EAAE,iBAAiB;oBACjC,iBAAiB,EAAE,oBAAoB;oBACvC,aAAa,EAAE,gBAAgB;oBAC/B,gBAAgB,EAAE,mBAAmB;iBACtC,CAAC,CAAC;aACJ;oBAAS;gBACR,WAAW,EAAE,CAAC;aACf;QACH,CAAC;KAAA;IAED;;;;OAIG;IACH,YAAY,CAAC,sBAAgC;QAC3C,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAC7D,MAAM,gBAAgB,GAA4B,EAAE,CAAC;QACrD,IAAI,gBAAgB,GAAa,CAAC,GAAG,aAAa,CAAC,CAAC;QAEpD,MAAM,yBAAyB,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACvE,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;YACtD,gBAAgB,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC;YAC/C,OAAO,eAAe,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,gBAAgB,GAAG,CAAC,GAAG,aAAa,EAAE,GAAG,yBAAyB,CAAC,CAAC;QACpE,MAAM,iBAAiB,GAAG,cAAc,CAAC,MAAM,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAC1D,CAAC;QACF,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAC7B,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAC1D,CAAC;QAEF,MAAM,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,EAAE,GAC/D,IAAI,CAAC,qBAAqB,CAAC;YACzB,gBAAgB;YAChB,iBAAiB;YACjB,SAAS;SACV,CAAC,CAAC;QAEL,IAAI,CAAC,MAAM,CAAC;YACV,aAAa,EAAE,gBAAgB;YAC/B,MAAM,EAAE,SAAS;YACjB,cAAc,EAAE,iBAAiB;YACjC,gBAAgB,EAAE,mBAAmB;YACrC,iBAAiB,EAAE,oBAAoB;YACvC,SAAS,EAAE,YAAY;SACxB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACG,iBAAiB,CACrB,sBAA+B,EAC/B,gBAA4D;;;YAE5D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/C,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAC7D,MAAM,SAAS,GAAY,CAAC,GAAG,MAAM,CAAC,CAAC;YACvC,IAAI,iBAAiB,GAAY,CAAC,GAAG,cAAc,CAAC,CAAC;YAErD,IAAI;gBACF,sBAAsB,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;oBAC5C,MAAM,EACJ,OAAO,EACP,MAAM,EACN,QAAQ,EACR,KAAK,EACL,WAAW,EACX,QAAQ,EACR,IAAI,GACL,GAAG,UAAU,CAAC;oBACf,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;oBACtD,MAAM,QAAQ,GAAU;wBACtB,OAAO,EAAE,eAAe;wBACxB,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,QAAQ;wBACR,WAAW;wBACX,IAAI;qBACL,CAAC;oBACF,MAAM,qBAAqB,GAAG,SAAS,CAAC,IAAI,CAC1C,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,WAAW,EAAE,CAChE,CAAC;oBACF,IAAI,qBAAqB,EAAE;wBACzB,yCAAyC;wBACzC,MAAM,qBAAqB,GAAG,SAAS,CAAC,OAAO,CAC7C,qBAAqB,CACtB,CAAC;wBACF,SAAS,CAAC,qBAAqB,CAAC,GAAG,QAAQ,CAAC;qBAC7C;yBAAM;wBACL,MAAM,iBAAiB,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;wBACzD,IAAI,iBAAiB,KAAK,CAAC,CAAC,EAAE;4BAC5B,qBAAqB;4BACrB,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,IAAI,CAClD,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,WAAW,EAAE,CAChE,CAAC;4BACF,IAAI,qBAAqB,EAAE;gCACzB,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,OAAO,CACrD,qBAAqB,CACtB,CAAC;gCACF,iBAAiB,CAAC,qBAAqB,CAAC,GAAG,QAAQ,CAAC;6BACrD;iCAAM;gCACL,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;6BAClC;yBACF;qBACF;gBACH,CAAC,CAAC,CAAC;gBAEH,MAAM,EACJ,eAAe,EAAE,kBAAkB,EACnC,OAAO,EAAE,kBAAkB,GAC5B,GAAG,gBAAgB,IAAI,EAAE,CAAC;gBAE3B,MAAM,EAAE,YAAY,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC,qBAAqB,CACvE;oBACE,SAAS;oBACT,iBAAiB;oBACjB,kBAAkB;oBAClB,kBAAkB;iBACnB,CACF,CAAC;gBAEF,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;gBACjD,sJAAsJ;gBACtJ,iKAAiK;gBACjK,sGAAsG;gBACtG,iBAAiB;oBACf,CAAA,MAAA,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAG,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE,CAAC;gBAE3D,IAAI,CAAC,MAAM,CAAC;oBACV,MAAM,EAAE,SAAS;oBACjB,SAAS,EAAE,YAAY;oBACvB,cAAc,EAAE,iBAAiB;oBACjC,iBAAiB,EAAE,oBAAoB;iBACxC,CAAC,CAAC;aACJ;oBAAS;gBACR,WAAW,EAAE,CAAC;aACf;;KACF;IAED;;;;;;OAMG;IACG,eAAe,CAAC,YAAoB;;YACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;YAC1D,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE,CAAC;YACpE,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YACxB,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;OAKG;IACK,qBAAqB,CAC3B,SAAuB,EACvB,cAAkD;QAElD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAE9B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACrC,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;YAExD,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,KAAI,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,cAAc,CAAC,CAAA;gBACzD,CAAC,iCAAM,KAAK,KAAE,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,IACxD,CAAC,mBAAM,KAAK,CAAE,CAAC;QACnB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;OAOG;IACG,eAAe,CACnB,YAAoB,EACpB,eAAiC;;;YAEjC,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,YAAY,CAAC,CAAC;YAC3D,sEAAsE;YACtE,gCAAgC;YAChC,IAAI,CAAA,MAAA,2BAAY,CAAC,eAAe,CAAC,0CAAE,MAAM,MAAK,IAAI,EAAE;gBAClD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;aAC9B;iBAAM,IAAI,CAAA,MAAA,2BAAY,CAAC,eAAe,CAAC,0CAAE,KAAK,MAAK,IAAI,EAAE;gBACxD,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aAC/B;YAED,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,CAC9C,YAAY,EACZ,6BAAS,EACT,eAAe,CAChB,CAAC;YACF,IAAI;gBACF,OAAO,MAAM,aAAa,CAAC,iBAAiB,CAAC,sCAAmB,CAAC,CAAC;aACnE;YAAC,OAAO,KAAU,EAAE;gBACnB,sEAAsE;gBACtE,4EAA4E;gBAC5E,8EAA8E;gBAC9E,wDAAwD;gBACxD,OAAO,KAAK,CAAC;aACd;;KACF;IAED,qBAAqB,CACnB,YAAoB,EACpB,GAAW,EACX,eAAiC;;QAEjC,MAAM,QAAQ,GAAG,eAAe;YAC9B,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,QAAQ;YACrD,CAAC,CAAC,MAAA,IAAI,CAAC,MAAM,0CAAE,QAAQ,CAAC;QAE1B,MAAM,YAAY,GAAG,IAAI,wBAAY,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,aAAa,GAAG,IAAI,oBAAQ,CAAC,YAAY,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;QACpE,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,iBAAiB;QACf,OAAO,IAAA,SAAM,GAAE,CAAC;IAClB,CAAC;IAED;;;;;;;;;;OAUG;IACG,UAAU,CAAC,EACf,KAAK,EACL,IAAI,EACJ,kBAAkB,EAClB,eAAe,GAMhB;;YACC,IAAI,IAAI,KAAK,wBAAK,EAAE;gBAClB,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,gBAAgB,CAAC,CAAC;aACxD;YAED,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YAExC,MAAM,kBAAkB,GAAuB;gBAC7C,KAAK;gBACL,EAAE,EAAE,IAAI,CAAC,iBAAiB,EAAE;gBAC5B,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;gBAChB,IAAI;gBACJ,kBAAkB,EAAE,kBAAkB,IAAI,eAAe;aAC1D,CAAC;YAEF,IAAA,iCAAoB,EAAC,KAAK,CAAC,CAAC;YAE5B,MAAM,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;YAEhD,IAAI,IAAI,CAAC;YACT,IAAI;gBACF,IAAI,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;aACrE;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,GAAG,SAAS,CAAC;aAClB;YAED,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;YACnD,MAAM,IAAI,CAAC,QAAQ,CAAC;gBAClB,OAAO;gBACP,MAAM;gBACN,QAAQ;gBACR,IAAI;gBACJ,KAAK;gBACL,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB;gBACzD,eAAe;aAChB,CAAC,CAAC;QACL,CAAC;KAAA;IAED;;;;;;;;;;;OAWG;IACH,qBAAqB,CAAC,MAMrB;QACC,MAAM,EACJ,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GACnB,GAAG,MAAM,CAAC;QACX,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QACtE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QAEjD,MAAM,sBAAsB,GAAG,kBAAkB,aAAlB,kBAAkB,cAAlB,kBAAkB,GAAI,eAAe,CAAC;QACrE,MAAM,kBAAkB,GAAG,kBAAkB,aAAlB,kBAAkB,cAAlB,kBAAkB,GAAI,OAAO,CAAC;QAEzD,IAAI,YAAY,GAAG,SAAS,CAAC;QAC7B,IACE,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM;YACjB,CAAC,SAAS;gBACR,SAAS;gBACT,SAAS,CAAC,kBAAkB,CAAC;gBAC7B,SAAS,CAAC,kBAAkB,CAAC,CAAC,sBAAsB,CAAC,CAAC,EACxD;YACA,MAAM,aAAa,GAAG,SAAS,CAAC,kBAAkB,CAAC,CAAC;YACpD,MAAM,gBAAgB,mCACjB,aAAa,GACb,EAAE,CAAC,sBAAsB,CAAC,EAAE,SAAS,EAAE,CAC3C,CAAC;YACF,YAAY,mCACP,SAAS,GACT,EAAE,CAAC,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAC9C,CAAC;SACH;QAED,IAAI,mBAAmB,GAAG,gBAAgB,CAAC;QAC3C,IACE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,MAAM;YACxB,CAAC,gBAAgB;gBACf,gBAAgB;gBAChB,gBAAgB,CAAC,kBAAkB,CAAC;gBACpC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,sBAAsB,CAAC,CAAC,EAC/D;YACA,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;YAClE,MAAM,uBAAuB,mCACxB,oBAAoB,GACpB,EAAE,CAAC,sBAAsB,CAAC,EAAE,gBAAgB,EAAE,CAClD,CAAC;YACF,mBAAmB,mCACd,gBAAgB,GAChB,EAAE,CAAC,kBAAkB,CAAC,EAAE,uBAAuB,EAAE,CACrD,CAAC;SACH;QAED,IAAI,oBAAoB,GAAG,iBAAiB,CAAC;QAC7C,IACE,CAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,MAAM;YACzB,CAAC,iBAAiB;gBAChB,iBAAiB;gBACjB,iBAAiB,CAAC,kBAAkB,CAAC;gBACrC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,sBAAsB,CAAC,CAAC,EAChE;YACA,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YACpE,MAAM,wBAAwB,mCACzB,qBAAqB,GACrB,EAAE,CAAC,sBAAsB,CAAC,EAAE,iBAAiB,EAAE,CACnD,CAAC;YACF,oBAAoB,mCACf,iBAAiB,GACjB,EAAE,CAAC,kBAAkB,CAAC,EAAE,wBAAwB,EAAE,CACtD,CAAC;SACH;QACD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;IACrE,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,IAAI,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;IAEK,gBAAgB,CAAC,kBAAsC;;YAC3D,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAC9B,+BAA+B,EAC/B;gBACE,EAAE,EAAE,kBAAkB,CAAC,EAAE;gBACzB,MAAM,EAAE,kCAAe;gBACvB,IAAI,EAAE,+BAAY,CAAC,UAAU;gBAC7B,WAAW,EAAE;oBACX,EAAE,EAAE,kBAAkB,CAAC,EAAE;oBACzB,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB;oBACzD,KAAK,EAAE;wBACL,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC,OAAO;wBACzC,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,QAAQ;wBAC3C,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM;wBACvC,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI;qBAC9C;iBACF;aACF,EACD,IAAI,CACL,CAAC;QACJ,CAAC;KAAA;CACF;AArvBD,4CAqvBC;AAED,kBAAe,gBAAgB,CAAC","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { AddApprovalRequest } from '@metamask/approval-controller';\nimport type {\n BaseConfig,\n BaseState,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport contractsMap from '@metamask/contract-metadata';\nimport {\n toChecksumHexAddress,\n ERC721_INTERFACE_ID,\n ORIGIN_METAMASK,\n ApprovalType,\n ERC20,\n} from '@metamask/controller-utils';\nimport { abiERC721 } from '@metamask/metamask-eth-abis';\nimport type {\n NetworkClientId,\n NetworkController,\n NetworkState,\n} from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { EventEmitter } from 'events';\nimport { v1 as random } from 'uuid';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport {\n formatAggregatorNames,\n formatIconUrlWithProxy,\n validateTokenToWatch,\n} from './assetsUtil';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from './token-service';\nimport type {\n TokenListMap,\n TokenListState,\n TokenListToken,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\n\n/**\n * @type TokensConfig\n *\n * Tokens controller configuration\n * @property selectedAddress - Vault selected address\n */\nexport interface TokensConfig extends BaseConfig {\n selectedAddress: string;\n chainId: Hex;\n provider: any;\n}\n\n/**\n * @type SuggestedAssetMeta\n *\n * Suggested asset by EIP747 meta data\n * @property id - Generated UUID associated with this suggested asset\n * @property time - Timestamp associated with this this suggested asset\n * @property type - Type type this suggested asset\n * @property asset - Asset suggested object\n * @property interactingAddress - Account address that requested watch asset\n */\ntype SuggestedAssetMeta = {\n id: string;\n time: number;\n type: string;\n asset: Token;\n interactingAddress: string;\n};\n\n/**\n * @type TokensState\n *\n * Assets controller state\n * @property tokens - List of tokens associated with the active network and address pair\n * @property ignoredTokens - List of ignoredTokens associated with the active network and address pair\n * @property detectedTokens - List of detected tokens associated with the active network and address pair\n * @property allTokens - Object containing tokens by network and account\n * @property allIgnoredTokens - Object containing hidden/ignored tokens by network and account\n * @property allDetectedTokens - Object containing tokens detected with non-zero balances\n */\nexport interface TokensState extends BaseState {\n tokens: Token[];\n ignoredTokens: string[];\n detectedTokens: Token[];\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allIgnoredTokens: { [chainId: Hex]: { [key: string]: string[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n}\n\n/**\n * The name of the {@link TokensController}.\n */\nconst controllerName = 'TokensController';\n\n/**\n * The external actions available to the {@link TokensController}.\n */\ntype AllowedActions = AddApprovalRequest;\n\n/**\n * The messenger of the {@link TokensController}.\n */\nexport type TokensControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n AllowedActions,\n never,\n AllowedActions['type'],\n never\n>;\n\n/**\n * Controller that stores assets and exposes convenience methods\n */\nexport class TokensController extends BaseController<\n TokensConfig,\n TokensState\n> {\n private readonly mutex = new Mutex();\n\n private abortController: AbortController;\n\n private readonly messagingSystem: TokensControllerMessenger;\n\n /**\n * Fetch metadata for a token.\n *\n * @param tokenAddress - The address of the token.\n * @returns The token metadata.\n */\n private async fetchTokenMetadata(\n tokenAddress: string,\n ): Promise<TokenListToken | undefined> {\n try {\n const token = await fetchTokenMetadata<TokenListToken>(\n this.config.chainId,\n tokenAddress,\n this.abortController.signal,\n );\n return token;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * EventEmitter instance used to listen to specific EIP747 events\n */\n hub = new EventEmitter();\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokensController';\n\n private readonly getERC20TokenName: AssetsContractController['getERC20TokenName'];\n\n private readonly getNetworkClientById: NetworkController['getNetworkClientById'];\n\n /**\n * Creates a TokensController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.\n * @param options.getERC20TokenName - Gets the ERC-20 token name.\n * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.\n * @param options.config - Initial options used to configure this controller.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messenger.\n */\n constructor({\n chainId: initialChainId,\n onPreferencesStateChange,\n onNetworkStateChange,\n onTokenListStateChange,\n getERC20TokenName,\n getNetworkClientById,\n config,\n state,\n messenger,\n }: {\n chainId: Hex;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n onTokenListStateChange: (\n listener: (tokenListState: TokenListState) => void,\n ) => void;\n getERC20TokenName: AssetsContractController['getERC20TokenName'];\n getNetworkClientById: NetworkController['getNetworkClientById'];\n config?: Partial<TokensConfig>;\n state?: Partial<TokensState>;\n messenger: TokensControllerMessenger;\n }) {\n super(config, state);\n\n this.defaultConfig = {\n selectedAddress: '',\n chainId: initialChainId,\n provider: undefined,\n ...config,\n };\n\n this.defaultState = {\n tokens: [],\n ignoredTokens: [],\n detectedTokens: [],\n allTokens: {},\n allIgnoredTokens: {},\n allDetectedTokens: {},\n ...state,\n };\n\n this.initialize();\n this.abortController = new AbortController();\n this.getERC20TokenName = getERC20TokenName;\n this.getNetworkClientById = getNetworkClientById;\n\n this.messagingSystem = messenger;\n\n onPreferencesStateChange(({ selectedAddress }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = this.config;\n this.configure({ selectedAddress });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { selectedAddress } = this.config;\n const { chainId } = providerConfig;\n this.abortController.abort();\n this.abortController = new AbortController();\n this.configure({ chainId });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onTokenListStateChange(({ tokenList }) => {\n const { tokens } = this.state;\n if (tokens.length && !tokens[0].name) {\n this.updateTokensAttribute(tokenList, 'name');\n }\n });\n }\n\n /**\n * Adds a token to the stored token list.\n *\n * @param options - The method argument object.\n * @param options.address - Hex address of the token contract.\n * @param options.symbol - Symbol of the token.\n * @param options.decimals - Number of decimals the token uses.\n * @param options.name - Name of the token.\n * @param options.image - Image of the token.\n * @param options.interactingAddress - The address of the account to add a token to.\n * @param options.networkClientId - Network Client ID.\n * @returns Current token list.\n */\n async addToken({\n address,\n symbol,\n decimals,\n name,\n image,\n interactingAddress,\n networkClientId,\n }: {\n address: string;\n symbol: string;\n decimals: number;\n name?: string;\n image?: string;\n interactingAddress?: string;\n networkClientId?: NetworkClientId;\n }): Promise<Token[]> {\n const { chainId, selectedAddress } = 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 =\n this.getNetworkClientById(networkClientId).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.config.chainId) {\n throw new Error(\n 'TokensController Error: Switched networks while adding token',\n );\n }\n const newEntry: Token = {\n address,\n symbol,\n decimals,\n image:\n image ||\n formatIconUrlWithProxy({\n chainId: currentChainId,\n tokenAddress: address,\n }),\n isERC721,\n aggregators: formatAggregatorNames(tokenMetadata?.aggregators || []),\n name,\n };\n const previousEntry = newTokens.find(\n (token) => token.address.toLowerCase() === address.toLowerCase(),\n );\n if (previousEntry) {\n const previousIndex = newTokens.indexOf(previousEntry);\n newTokens[previousIndex] = newEntry;\n } else {\n newTokens.push(newEntry);\n }\n\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => tokenAddress.toLowerCase() !== address.toLowerCase(),\n );\n const newDetectedTokens = detectedTokens.filter(\n (token) => token.address.toLowerCase() !== address.toLowerCase(),\n );\n\n const { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens } =\n this._getNewAllTokensState({\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n interactingAddress: accountAddress,\n interactingChainId: currentChainId,\n });\n\n let newState: Partial<TokensState> = {\n allTokens: newAllTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n };\n\n // Only update active tokens if user is interacting with their active wallet account.\n if (isInteractingWithWalletAccount) {\n newState = {\n ...newState,\n tokens: newTokens,\n ignoredTokens: newIgnoredTokens,\n detectedTokens: newDetectedTokens,\n };\n }\n\n this.update(newState);\n return newTokens;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Add a batch of tokens.\n *\n * @param tokensToImport - Array of tokens to import.\n * @param networkClientId - Optional network client ID used to determine interacting chain ID.\n */\n async addTokens(tokensToImport: Token[], networkClientId?: NetworkClientId) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const importedTokensMap: { [key: string]: true } = {};\n // Used later to dedupe imported tokens\n const newTokensMap = tokens.reduce((output, current) => {\n output[current.address] = current;\n return output;\n }, {} as { [address: string]: Token });\n try {\n tokensToImport.forEach((tokenToAdd) => {\n const { address, symbol, decimals, image, aggregators, name } =\n tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const formattedToken: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n aggregators,\n name,\n };\n newTokensMap[address] = formattedToken;\n importedTokensMap[address.toLowerCase()] = true;\n return formattedToken;\n });\n const newTokens = Object.values(newTokensMap);\n\n const newDetectedTokens = detectedTokens.filter(\n (token) => !importedTokensMap[token.address.toLowerCase()],\n );\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => !newTokensMap[tokenAddress.toLowerCase()],\n );\n\n let interactingChainId;\n if (networkClientId) {\n interactingChainId =\n this.getNetworkClientById(networkClientId).configuration.chainId;\n }\n\n const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } =\n this._getNewAllTokensState({\n newTokens,\n newDetectedTokens,\n newIgnoredTokens,\n interactingChainId,\n });\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n ignoredTokens: newIgnoredTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Ignore a batch of tokens.\n *\n * @param tokenAddressesToIgnore - Array of token addresses to ignore.\n */\n ignoreTokens(tokenAddressesToIgnore: string[]) {\n const { ignoredTokens, detectedTokens, tokens } = this.state;\n const ignoredTokensMap: { [key: string]: true } = {};\n let newIgnoredTokens: string[] = [...ignoredTokens];\n\n const checksummedTokenAddresses = tokenAddressesToIgnore.map((address) => {\n const checksumAddress = toChecksumHexAddress(address);\n ignoredTokensMap[address.toLowerCase()] = true;\n return checksumAddress;\n });\n newIgnoredTokens = [...ignoredTokens, ...checksummedTokenAddresses];\n const newDetectedTokens = detectedTokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n const newTokens = tokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n\n const { newAllIgnoredTokens, newAllDetectedTokens, newAllTokens } =\n this._getNewAllTokensState({\n newIgnoredTokens,\n newDetectedTokens,\n newTokens,\n });\n\n this.update({\n ignoredTokens: newIgnoredTokens,\n tokens: newTokens,\n detectedTokens: newDetectedTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n allTokens: newAllTokens,\n });\n }\n\n /**\n * Adds a batch of detected tokens to the stored token list.\n *\n * @param incomingDetectedTokens - Array of detected tokens to be added or updated.\n * @param detectionDetails - An object containing the chain ID and address of the currently selected network on which the incomingDetectedTokens were detected.\n * @param detectionDetails.selectedAddress - the account address on which the incomingDetectedTokens were detected.\n * @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.\n */\n async addDetectedTokens(\n incomingDetectedTokens: Token[],\n detectionDetails?: { selectedAddress: string; chainId: Hex },\n ) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const newTokens: Token[] = [...tokens];\n let newDetectedTokens: Token[] = [...detectedTokens];\n\n try {\n incomingDetectedTokens.forEach((tokenToAdd) => {\n const {\n address,\n symbol,\n decimals,\n image,\n aggregators,\n isERC721,\n name,\n } = tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const newEntry: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n isERC721,\n aggregators,\n name,\n };\n const previousImportedEntry = newTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousImportedEntry) {\n // Update existing data of imported token\n const previousImportedIndex = newTokens.indexOf(\n previousImportedEntry,\n );\n newTokens[previousImportedIndex] = newEntry;\n } else {\n const ignoredTokenIndex = ignoredTokens.indexOf(address);\n if (ignoredTokenIndex === -1) {\n // Add detected token\n const previousDetectedEntry = newDetectedTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousDetectedEntry) {\n const previousDetectedIndex = newDetectedTokens.indexOf(\n previousDetectedEntry,\n );\n newDetectedTokens[previousDetectedIndex] = newEntry;\n } else {\n newDetectedTokens.push(newEntry);\n }\n }\n }\n });\n\n const {\n selectedAddress: interactingAddress,\n chainId: interactingChainId,\n } = detectionDetails || {};\n\n const { newAllTokens, newAllDetectedTokens } = this._getNewAllTokensState(\n {\n newTokens,\n newDetectedTokens,\n interactingAddress,\n interactingChainId,\n },\n );\n\n const { chainId, selectedAddress } = this.config;\n // if the newly added detectedTokens were detected on (and therefore added to) a different chainId/selectedAddress than the currently configured combo\n // the newDetectedTokens (which should contain the detectedTokens on the current chainId/address combo) needs to be repointed to the current chainId/address pair\n // if the detectedTokens were detected on the current chainId/address then this won't change anything.\n newDetectedTokens =\n newAllDetectedTokens?.[chainId]?.[selectedAddress] || [];\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Adds isERC721 field to token object. This is called when a user attempts to add tokens that\n * were previously added which do not yet had isERC721 field.\n *\n * @param tokenAddress - The contract address of the token requiring the isERC721 field added.\n * @returns The new token object with the added isERC721 field.\n */\n async updateTokenType(tokenAddress: string) {\n const isERC721 = await this._detectIsERC721(tokenAddress);\n const { tokens } = this.state;\n const tokenIndex = tokens.findIndex((token) => {\n return token.address.toLowerCase() === tokenAddress.toLowerCase();\n });\n tokens[tokenIndex].isERC721 = isERC721;\n this.update({ tokens });\n return tokens[tokenIndex];\n }\n\n /**\n * This is a function that updates the tokens name for the tokens name if it is not defined.\n *\n * @param tokenList - Represents the fetched token list from service API\n * @param tokenAttribute - Represents the token attribute that we want to update on the token list\n */\n private updateTokensAttribute(\n tokenList: TokenListMap,\n tokenAttribute: keyof Token & keyof TokenListToken,\n ) {\n const { tokens } = this.state;\n\n const newTokens = tokens.map((token) => {\n const newToken = tokenList[token.address.toLowerCase()];\n\n return !token[tokenAttribute] && newToken?.[tokenAttribute]\n ? { ...token, [tokenAttribute]: newToken[tokenAttribute] }\n : { ...token };\n });\n\n this.update({ tokens: newTokens });\n }\n\n /**\n * Detects whether or not a token is ERC-721 compatible.\n *\n * @param tokenAddress - The token contract address.\n * @param networkClientId - Optional network client ID to fetch contract info with.\n * @returns A boolean indicating whether the token address passed in supports the EIP-721\n * interface.\n */\n async _detectIsERC721(\n tokenAddress: string,\n networkClientId?: NetworkClientId,\n ) {\n const checksumAddress = toChecksumHexAddress(tokenAddress);\n // if this token is already in our contract metadata map we don't need\n // to check against the contract\n if (contractsMap[checksumAddress]?.erc721 === true) {\n return Promise.resolve(true);\n } else if (contractsMap[checksumAddress]?.erc20 === true) {\n return Promise.resolve(false);\n }\n\n const tokenContract = this._createEthersContract(\n tokenAddress,\n abiERC721,\n networkClientId,\n );\n try {\n return await tokenContract.supportsInterface(ERC721_INTERFACE_ID);\n } catch (error: any) {\n // currently we see a variety of errors across different networks when\n // token contracts are not ERC721 compatible. We need to figure out a better\n // way of differentiating token interface types but for now if we get an error\n // we have to assume the token is not ERC721 compatible.\n return false;\n }\n }\n\n _createEthersContract(\n tokenAddress: string,\n abi: string,\n networkClientId?: NetworkClientId,\n ): Contract {\n const provider = networkClientId\n ? this.getNetworkClientById(networkClientId).provider\n : this.config?.provider;\n\n const web3provider = new Web3Provider(provider);\n const tokenContract = new Contract(tokenAddress, abi, web3provider);\n return tokenContract;\n }\n\n _generateRandomId(): string {\n return random();\n }\n\n /**\n * Adds a new suggestedAsset to the list of watched assets.\n * Parameters will be validated according to the asset type being watched.\n *\n * @param options - The method options.\n * @param options.asset - The asset to be watched. For now only ERC20 tokens are accepted.\n * @param options.type - The asset type.\n * @param options.interactingAddress - The address of the account that is requesting to watch the asset.\n * @param options.networkClientId - Network Client ID.\n * @returns Object containing a Promise resolving to the suggestedAsset address if accepted.\n */\n async watchAsset({\n asset,\n type,\n interactingAddress,\n networkClientId,\n }: {\n asset: Token;\n type: string;\n interactingAddress?: string;\n networkClientId?: NetworkClientId;\n }): Promise<void> {\n if (type !== ERC20) {\n throw new Error(`Asset of type ${type} not supported`);\n }\n\n const { selectedAddress } = this.config;\n\n const suggestedAssetMeta: SuggestedAssetMeta = {\n asset,\n id: this._generateRandomId(),\n time: Date.now(),\n type,\n interactingAddress: interactingAddress || selectedAddress,\n };\n\n validateTokenToWatch(asset);\n\n await this._requestApproval(suggestedAssetMeta);\n\n let name;\n try {\n name = await this.getERC20TokenName(asset.address, networkClientId);\n } catch (error) {\n name = undefined;\n }\n\n const { address, symbol, decimals, image } = asset;\n await this.addToken({\n address,\n symbol,\n decimals,\n name,\n image,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n networkClientId,\n });\n }\n\n /**\n * Takes a new tokens and ignoredTokens array for the current network/account combination\n * and returns new allTokens and allIgnoredTokens state to update to.\n *\n * @param params - Object that holds token params.\n * @param params.newTokens - The new tokens to set for the current network and selected account.\n * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.\n * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.\n * @param params.interactingAddress - The account address to use to store the tokens.\n * @param params.interactingChainId - The chainId to use to store the tokens.\n * @returns The updated `allTokens` and `allIgnoredTokens` state.\n */\n _getNewAllTokensState(params: {\n newTokens?: Token[];\n newIgnoredTokens?: string[];\n newDetectedTokens?: Token[];\n interactingAddress?: string;\n interactingChainId?: Hex;\n }) {\n const {\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n interactingAddress,\n interactingChainId,\n } = params;\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId, selectedAddress } = this.config;\n\n const userAddressToAddTokens = interactingAddress ?? selectedAddress;\n const chainIdToAddTokens = interactingChainId ?? chainId;\n\n let newAllTokens = allTokens;\n if (\n newTokens?.length ||\n (newTokens &&\n allTokens &&\n allTokens[chainIdToAddTokens] &&\n allTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkTokens = allTokens[chainIdToAddTokens];\n const newNetworkTokens = {\n ...networkTokens,\n ...{ [userAddressToAddTokens]: newTokens },\n };\n newAllTokens = {\n ...allTokens,\n ...{ [chainIdToAddTokens]: newNetworkTokens },\n };\n }\n\n let newAllIgnoredTokens = allIgnoredTokens;\n if (\n newIgnoredTokens?.length ||\n (newIgnoredTokens &&\n allIgnoredTokens &&\n allIgnoredTokens[chainIdToAddTokens] &&\n allIgnoredTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkIgnoredTokens = allIgnoredTokens[chainIdToAddTokens];\n const newIgnoredNetworkTokens = {\n ...networkIgnoredTokens,\n ...{ [userAddressToAddTokens]: newIgnoredTokens },\n };\n newAllIgnoredTokens = {\n ...allIgnoredTokens,\n ...{ [chainIdToAddTokens]: newIgnoredNetworkTokens },\n };\n }\n\n let newAllDetectedTokens = allDetectedTokens;\n if (\n newDetectedTokens?.length ||\n (newDetectedTokens &&\n allDetectedTokens &&\n allDetectedTokens[chainIdToAddTokens] &&\n allDetectedTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkDetectedTokens = allDetectedTokens[chainIdToAddTokens];\n const newDetectedNetworkTokens = {\n ...networkDetectedTokens,\n ...{ [userAddressToAddTokens]: newDetectedTokens },\n };\n newAllDetectedTokens = {\n ...allDetectedTokens,\n ...{ [chainIdToAddTokens]: newDetectedNetworkTokens },\n };\n }\n return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };\n }\n\n /**\n * Removes all tokens from the ignored list.\n */\n clearIgnoredTokens() {\n this.update({ ignoredTokens: [], allIgnoredTokens: {} });\n }\n\n async _requestApproval(suggestedAssetMeta: SuggestedAssetMeta) {\n return this.messagingSystem.call(\n 'ApprovalController:addRequest',\n {\n id: suggestedAssetMeta.id,\n origin: ORIGIN_METAMASK,\n type: ApprovalType.WatchAsset,\n requestData: {\n id: suggestedAssetMeta.id,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n asset: {\n address: suggestedAssetMeta.asset.address,\n decimals: suggestedAssetMeta.asset.decimals,\n symbol: suggestedAssetMeta.asset.symbol,\n image: suggestedAssetMeta.asset.image || null,\n },\n },\n },\n true,\n );\n }\n}\n\nexport default TokensController;\n"]}
|
|
1
|
+
{"version":3,"file":"TokensController.js","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wDAAoD;AACpD,wDAAwD;AAOxD,+DAA2D;AAC3D,oFAAuD;AACvD,iEAMoC;AACpC,mEAAwD;AAQxD,6CAAoC;AACpC,mCAAsC;AACtC,+BAAoC;AAGpC,6CAIsB;AACtB,mDAGyB;AA0DzB;;GAEG;AACH,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAkB1C;;GAEG;AACH,MAAa,gBAAiB,SAAQ,gCAGrC;IAgDC;;;;;;;;;;;;;OAaG;IACH,YAAY,EACV,OAAO,EAAE,cAAc,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,MAAM,EACN,KAAK,EACL,SAAS,GAiBV;QACC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAxFN,UAAK,GAAG,IAAI,mBAAK,EAAE,CAAC;QAiCrC;;WAEG;QACH,QAAG,GAAG,IAAI,qBAAY,EAAE,CAAC;QAEzB;;WAEG;QACM,SAAI,GAAG,kBAAkB,CAAC;QAiDjC,IAAI,CAAC,aAAa,mBAChB,eAAe,EAAE,EAAE,EACnB,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,SAAS,IAChB,MAAM,CACV,CAAC;QAEF,IAAI,CAAC,YAAY,mBACf,MAAM,EAAE,EAAE,EACV,aAAa,EAAE,EAAE,EACjB,cAAc,EAAE,EAAE,EAClB,SAAS,EAAE,EAAE,EACb,gBAAgB,EAAE,EAAE,EACpB,iBAAiB,EAAE,EAAE,IAClB,KAAK,CACT,CAAC;QAEF,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC7C,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,oBAAoB,GAAG,oBAAoB,CAAC;QAEjD,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QAEjC,wBAAwB,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE;;YAC/C,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACtE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YAChC,IAAI,CAAC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC;gBACV,MAAM,EAAE,CAAA,MAAA,SAAS,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACnD,aAAa,EAAE,CAAA,MAAA,gBAAgB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACjE,cAAc,EAAE,CAAA,MAAA,iBAAiB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;aACpE,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,oBAAoB,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE;;YAC1C,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACtE,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YACxC,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC;YACnC,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;YAC7C,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC;gBACV,MAAM,EAAE,CAAA,MAAA,SAAS,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACnD,aAAa,EAAE,CAAA,MAAA,gBAAgB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;gBACjE,cAAc,EAAE,CAAA,MAAA,iBAAiB,CAAC,OAAO,CAAC,0CAAG,eAAe,CAAC,KAAI,EAAE;aACpE,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,sBAAsB,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;YACvC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBACpC,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;aAC/C;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IA3ID;;;;;OAKG;IACW,kBAAkB,CAC9B,YAAoB;;YAEpB,IAAI;gBACF,MAAM,KAAK,GAAG,MAAM,IAAA,kCAAkB,EACpC,IAAI,CAAC,MAAM,CAAC,OAAO,EACnB,YAAY,EACZ,IAAI,CAAC,eAAe,CAAC,MAAM,CAC5B,CAAC;gBACF,OAAO,KAAK,CAAC;aACd;YAAC,OAAO,KAAK,EAAE;gBACd,IACE,KAAK,YAAY,KAAK;oBACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,+CAA+B,CAAC,EACvD;oBACA,OAAO,SAAS,CAAC;iBAClB;gBACD,MAAM,KAAK,CAAC;aACb;QACH,CAAC;KAAA;IAoHD;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,EACb,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,kBAAkB,EAClB,eAAe,GAShB;;;YACC,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YACjD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/C,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACtE,IAAI,cAAc,GAAG,OAAO,CAAC;YAC7B,IAAI,eAAe,EAAE;gBACnB,cAAc;oBACZ,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC;aACpE;YAED,MAAM,cAAc,GAAG,kBAAkB,IAAI,eAAe,CAAC;YAC7D,MAAM,8BAA8B,GAAG,cAAc,KAAK,eAAe,CAAC;YAE1E,IAAI;gBACF,OAAO,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;gBACxC,MAAM,MAAM,GAAG,CAAA,MAAA,SAAS,CAAC,cAAc,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBACjE,MAAM,aAAa,GACjB,CAAA,MAAA,gBAAgB,CAAC,cAAc,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBAC3D,MAAM,cAAc,GAClB,CAAA,MAAA,iBAAiB,CAAC,cAAc,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBAC5D,MAAM,SAAS,GAAY,CAAC,GAAG,MAAM,CAAC,CAAC;gBACvC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;oBAClD,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,eAAe,CAAC;oBAC9C,gEAAgE;oBAChE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;iBACjC,CAAC,CAAC;gBACH,8EAA8E;gBAC9E,IAAI,CAAC,eAAe,IAAI,cAAc,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;oBAC9D,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;iBACH;gBACD,MAAM,QAAQ,GAAU;oBACtB,OAAO;oBACP,MAAM;oBACN,QAAQ;oBACR,KAAK,EACH,KAAK;wBACL,IAAA,mCAAsB,EAAC;4BACrB,OAAO,EAAE,cAAc;4BACvB,YAAY,EAAE,OAAO;yBACtB,CAAC;oBACJ,QAAQ;oBACR,WAAW,EAAE,IAAA,kCAAqB,EAAC,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,WAAW,KAAI,EAAE,CAAC;oBACpE,IAAI;iBACL,CAAC;gBACF,MAAM,aAAa,GAAG,SAAS,CAAC,SAAS,CACvC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACjE,CAAC;gBACF,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE;oBACxB,SAAS,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;iBACrC;qBAAM;oBACL,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;iBAC1B;gBAED,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAC3C,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACvE,CAAC;gBACF,MAAM,iBAAiB,GAAG,cAAc,CAAC,MAAM,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACjE,CAAC;gBAEF,MAAM,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,GAC/D,IAAI,CAAC,qBAAqB,CAAC;oBACzB,SAAS;oBACT,gBAAgB;oBAChB,iBAAiB;oBACjB,kBAAkB,EAAE,cAAc;oBAClC,kBAAkB,EAAE,cAAc;iBACnC,CAAC,CAAC;gBAEL,IAAI,QAAQ,GAAyB;oBACnC,SAAS,EAAE,YAAY;oBACvB,gBAAgB,EAAE,mBAAmB;oBACrC,iBAAiB,EAAE,oBAAoB;iBACxC,CAAC;gBAEF,qFAAqF;gBACrF,IAAI,8BAA8B,EAAE;oBAClC,QAAQ,mCACH,QAAQ,KACX,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,gBAAgB,EAC/B,cAAc,EAAE,iBAAiB,GAClC,CAAC;iBACH;gBAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACtB,OAAO,SAAS,CAAC;aAClB;oBAAS;gBACR,WAAW,EAAE,CAAC;aACf;;KACF;IAED;;;;;OAKG;IACG,SAAS,CAAC,cAAuB,EAAE,eAAiC;;YACxE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/C,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAC7D,MAAM,iBAAiB,GAA4B,EAAE,CAAC;YACtD,uCAAuC;YACvC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;gBACrD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;gBAClC,OAAO,MAAM,CAAC;YAChB,CAAC,EAAE,EAAkC,CAAC,CAAC;YACvC,IAAI;gBACF,cAAc,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;oBACpC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,GAC3D,UAAU,CAAC;oBACb,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;oBACtD,MAAM,cAAc,GAAU;wBAC5B,OAAO,EAAE,eAAe;wBACxB,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,WAAW;wBACX,IAAI;qBACL,CAAC;oBACF,YAAY,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC;oBACvC,iBAAiB,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC;oBAChD,OAAO,cAAc,CAAC;gBACxB,CAAC,CAAC,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;gBAE9C,MAAM,iBAAiB,GAAG,cAAc,CAAC,MAAM,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAC3D,CAAC;gBACF,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAC3C,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAC5D,CAAC;gBAEF,IAAI,kBAAkB,CAAC;gBACvB,IAAI,eAAe,EAAE;oBACnB,kBAAkB;wBAChB,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC;iBACpE;gBAED,MAAM,EAAE,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,GAC/D,IAAI,CAAC,qBAAqB,CAAC;oBACzB,SAAS;oBACT,iBAAiB;oBACjB,gBAAgB;oBAChB,kBAAkB;iBACnB,CAAC,CAAC;gBAEL,IAAI,CAAC,MAAM,CAAC;oBACV,MAAM,EAAE,SAAS;oBACjB,SAAS,EAAE,YAAY;oBACvB,cAAc,EAAE,iBAAiB;oBACjC,iBAAiB,EAAE,oBAAoB;oBACvC,aAAa,EAAE,gBAAgB;oBAC/B,gBAAgB,EAAE,mBAAmB;iBACtC,CAAC,CAAC;aACJ;oBAAS;gBACR,WAAW,EAAE,CAAC;aACf;QACH,CAAC;KAAA;IAED;;;;OAIG;IACH,YAAY,CAAC,sBAAgC;QAC3C,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAC7D,MAAM,gBAAgB,GAA4B,EAAE,CAAC;QACrD,IAAI,gBAAgB,GAAa,CAAC,GAAG,aAAa,CAAC,CAAC;QAEpD,MAAM,yBAAyB,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACvE,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;YACtD,gBAAgB,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC;YAC/C,OAAO,eAAe,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,gBAAgB,GAAG,CAAC,GAAG,aAAa,EAAE,GAAG,yBAAyB,CAAC,CAAC;QACpE,MAAM,iBAAiB,GAAG,cAAc,CAAC,MAAM,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAC1D,CAAC;QACF,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAC7B,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAC1D,CAAC;QAEF,MAAM,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,EAAE,GAC/D,IAAI,CAAC,qBAAqB,CAAC;YACzB,gBAAgB;YAChB,iBAAiB;YACjB,SAAS;SACV,CAAC,CAAC;QAEL,IAAI,CAAC,MAAM,CAAC;YACV,aAAa,EAAE,gBAAgB;YAC/B,MAAM,EAAE,SAAS;YACjB,cAAc,EAAE,iBAAiB;YACjC,gBAAgB,EAAE,mBAAmB;YACrC,iBAAiB,EAAE,oBAAoB;YACvC,SAAS,EAAE,YAAY;SACxB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACG,iBAAiB,CACrB,sBAA+B,EAC/B,gBAA4D;;;YAE5D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAE/C,8CAA8C;YAC9C,MAAM,OAAO,GAAG,MAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,OAAO,mCAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;YACjE,MAAM,cAAc,GAClB,MAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,eAAe,mCAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;YAEnE,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACtE,IAAI,SAAS,GAAG,CAAC,GAAG,CAAC,MAAA,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAG,OAAO,CAAC,0CAAG,cAAc,CAAC,mCAAI,EAAE,CAAC,CAAC,CAAC;YACpE,IAAI,iBAAiB,GAAG;gBACtB,GAAG,CAAC,MAAA,MAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAG,OAAO,CAAC,0CAAG,cAAc,CAAC,mCAAI,EAAE,CAAC;aAC1D,CAAC;YAEF,IAAI;gBACF,sBAAsB,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;;oBAC5C,MAAM,EACJ,OAAO,EACP,MAAM,EACN,QAAQ,EACR,KAAK,EACL,WAAW,EACX,QAAQ,EACR,IAAI,GACL,GAAG,UAAU,CAAC;oBACf,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC;oBACtD,MAAM,QAAQ,GAAU;wBACtB,OAAO,EAAE,eAAe;wBACxB,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,QAAQ;wBACR,WAAW;wBACX,IAAI;qBACL,CAAC;oBACF,MAAM,qBAAqB,GAAG,SAAS,CAAC,SAAS,CAC/C,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,WAAW,EAAE,CAChE,CAAC;oBACF,IAAI,qBAAqB,KAAK,CAAC,CAAC,EAAE;wBAChC,yCAAyC;wBACzC,SAAS,CAAC,qBAAqB,CAAC,GAAG,QAAQ,CAAC;qBAC7C;yBAAM;wBACL,MAAM,iBAAiB,GACrB,MAAA,MAAA,MAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAG,OAAO,CAAC,0CAAG,cAAc,CAAC,0CAAE,OAAO,CAAC,OAAO,CAAC,mCAC/D,CAAC,CAAC,CAAC;wBAEL,IAAI,iBAAiB,KAAK,CAAC,CAAC,EAAE;4BAC5B,qBAAqB;4BACrB,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,SAAS,CACvD,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,WAAW,EAAE,CAChE,CAAC;4BACF,IAAI,qBAAqB,KAAK,CAAC,CAAC,EAAE;gCAChC,iBAAiB,CAAC,qBAAqB,CAAC,GAAG,QAAQ,CAAC;6BACrD;iCAAM;gCACL,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;6BAClC;yBACF;qBACF;gBACH,CAAC,CAAC,CAAC;gBAEH,MAAM,EAAE,YAAY,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC,qBAAqB,CACvE;oBACE,SAAS;oBACT,iBAAiB;oBACjB,kBAAkB,EAAE,cAAc;oBAClC,kBAAkB,EAAE,OAAO;iBAC5B,CACF,CAAC;gBAEF,8FAA8F;gBAC9F,6FAA6F;gBAC7F,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,GAC9D,IAAI,CAAC,MAAM,CAAC;gBAEd,SAAS,GAAG,CAAA,MAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAG,YAAY,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBACjE,iBAAiB;oBACf,CAAA,MAAA,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAG,YAAY,CAAC,0CAAG,cAAc,CAAC,KAAI,EAAE,CAAC;gBAE/D,IAAI,CAAC,MAAM,CAAC;oBACV,MAAM,EAAE,SAAS;oBACjB,SAAS,EAAE,YAAY;oBACvB,cAAc,EAAE,iBAAiB;oBACjC,iBAAiB,EAAE,oBAAoB;iBACxC,CAAC,CAAC;aACJ;oBAAS;gBACR,WAAW,EAAE,CAAC;aACf;;KACF;IAED;;;;;;OAMG;IACG,eAAe,CAAC,YAAoB;;YACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;YAC1D,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE,CAAC;YACpE,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YACxB,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;OAKG;IACK,qBAAqB,CAC3B,SAAuB,EACvB,cAAkD;QAElD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAE9B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACrC,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;YAExD,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,KAAI,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,cAAc,CAAC,CAAA;gBACzD,CAAC,iCAAM,KAAK,KAAE,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,IACxD,CAAC,mBAAM,KAAK,CAAE,CAAC;QACnB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;OAOG;IACG,eAAe,CACnB,YAAoB,EACpB,eAAiC;;;YAEjC,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,YAAY,CAAC,CAAC;YAC3D,sEAAsE;YACtE,gCAAgC;YAChC,IAAI,CAAA,MAAA,2BAAY,CAAC,eAAe,CAAC,0CAAE,MAAM,MAAK,IAAI,EAAE;gBAClD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;aAC9B;iBAAM,IAAI,CAAA,MAAA,2BAAY,CAAC,eAAe,CAAC,0CAAE,KAAK,MAAK,IAAI,EAAE;gBACxD,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aAC/B;YAED,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,CAC9C,YAAY,EACZ,6BAAS,EACT,eAAe,CAChB,CAAC;YACF,IAAI;gBACF,OAAO,MAAM,aAAa,CAAC,iBAAiB,CAAC,sCAAmB,CAAC,CAAC;aACnE;YAAC,OAAO,KAAU,EAAE;gBACnB,sEAAsE;gBACtE,4EAA4E;gBAC5E,8EAA8E;gBAC9E,wDAAwD;gBACxD,OAAO,KAAK,CAAC;aACd;;KACF;IAED,qBAAqB,CACnB,YAAoB,EACpB,GAAW,EACX,eAAiC;;QAEjC,MAAM,QAAQ,GAAG,eAAe;YAC9B,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,QAAQ;YACrD,CAAC,CAAC,MAAA,IAAI,CAAC,MAAM,0CAAE,QAAQ,CAAC;QAE1B,MAAM,YAAY,GAAG,IAAI,wBAAY,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,aAAa,GAAG,IAAI,oBAAQ,CAAC,YAAY,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;QACpE,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,iBAAiB;QACf,OAAO,IAAA,SAAM,GAAE,CAAC;IAClB,CAAC;IAED;;;;;;;;;;OAUG;IACG,UAAU,CAAC,EACf,KAAK,EACL,IAAI,EACJ,kBAAkB,EAClB,eAAe,GAMhB;;YACC,IAAI,IAAI,KAAK,wBAAK,EAAE;gBAClB,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,gBAAgB,CAAC,CAAC;aACxD;YAED,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YAExC,MAAM,kBAAkB,GAAuB;gBAC7C,KAAK;gBACL,EAAE,EAAE,IAAI,CAAC,iBAAiB,EAAE;gBAC5B,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;gBAChB,IAAI;gBACJ,kBAAkB,EAAE,kBAAkB,IAAI,eAAe;aAC1D,CAAC;YAEF,IAAA,iCAAoB,EAAC,KAAK,CAAC,CAAC;YAE5B,MAAM,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;YAEhD,IAAI,IAAI,CAAC;YACT,IAAI;gBACF,IAAI,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;aACrE;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,GAAG,SAAS,CAAC;aAClB;YAED,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;YACnD,MAAM,IAAI,CAAC,QAAQ,CAAC;gBAClB,OAAO;gBACP,MAAM;gBACN,QAAQ;gBACR,IAAI;gBACJ,KAAK;gBACL,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB;gBACzD,eAAe;aAChB,CAAC,CAAC;QACL,CAAC;KAAA;IAED;;;;;;;;;;;OAWG;IACH,qBAAqB,CAAC,MAMrB;QACC,MAAM,EACJ,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GACnB,GAAG,MAAM,CAAC;QACX,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QACtE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QAEjD,MAAM,sBAAsB,GAAG,kBAAkB,aAAlB,kBAAkB,cAAlB,kBAAkB,GAAI,eAAe,CAAC;QACrE,MAAM,kBAAkB,GAAG,kBAAkB,aAAlB,kBAAkB,cAAlB,kBAAkB,GAAI,OAAO,CAAC;QAEzD,IAAI,YAAY,GAAG,SAAS,CAAC;QAC7B,IACE,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM;YACjB,CAAC,SAAS;gBACR,SAAS;gBACT,SAAS,CAAC,kBAAkB,CAAC;gBAC7B,SAAS,CAAC,kBAAkB,CAAC,CAAC,sBAAsB,CAAC,CAAC,EACxD;YACA,MAAM,aAAa,GAAG,SAAS,CAAC,kBAAkB,CAAC,CAAC;YACpD,MAAM,gBAAgB,mCACjB,aAAa,GACb,EAAE,CAAC,sBAAsB,CAAC,EAAE,SAAS,EAAE,CAC3C,CAAC;YACF,YAAY,mCACP,SAAS,GACT,EAAE,CAAC,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAC9C,CAAC;SACH;QAED,IAAI,mBAAmB,GAAG,gBAAgB,CAAC;QAC3C,IACE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,MAAM;YACxB,CAAC,gBAAgB;gBACf,gBAAgB;gBAChB,gBAAgB,CAAC,kBAAkB,CAAC;gBACpC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,sBAAsB,CAAC,CAAC,EAC/D;YACA,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;YAClE,MAAM,uBAAuB,mCACxB,oBAAoB,GACpB,EAAE,CAAC,sBAAsB,CAAC,EAAE,gBAAgB,EAAE,CAClD,CAAC;YACF,mBAAmB,mCACd,gBAAgB,GAChB,EAAE,CAAC,kBAAkB,CAAC,EAAE,uBAAuB,EAAE,CACrD,CAAC;SACH;QAED,IAAI,oBAAoB,GAAG,iBAAiB,CAAC;QAC7C,IACE,CAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,MAAM;YACzB,CAAC,iBAAiB;gBAChB,iBAAiB;gBACjB,iBAAiB,CAAC,kBAAkB,CAAC;gBACrC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,sBAAsB,CAAC,CAAC,EAChE;YACA,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YACpE,MAAM,wBAAwB,mCACzB,qBAAqB,GACrB,EAAE,CAAC,sBAAsB,CAAC,EAAE,iBAAiB,EAAE,CACnD,CAAC;YACF,oBAAoB,mCACf,iBAAiB,GACjB,EAAE,CAAC,kBAAkB,CAAC,EAAE,wBAAwB,EAAE,CACtD,CAAC;SACH;QACD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;IACrE,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,IAAI,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;IAEK,gBAAgB,CAAC,kBAAsC;;YAC3D,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAC9B,+BAA+B,EAC/B;gBACE,EAAE,EAAE,kBAAkB,CAAC,EAAE;gBACzB,MAAM,EAAE,kCAAe;gBACvB,IAAI,EAAE,+BAAY,CAAC,UAAU;gBAC7B,WAAW,EAAE;oBACX,EAAE,EAAE,kBAAkB,CAAC,EAAE;oBACzB,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB;oBACzD,KAAK,EAAE;wBACL,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC,OAAO;wBACzC,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,QAAQ;wBAC3C,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM;wBACvC,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI;qBAC9C;iBACF;aACF,EACD,IAAI,CACL,CAAC;QACJ,CAAC;KAAA;CACF;AAtvBD,4CAsvBC;AAED,kBAAe,gBAAgB,CAAC","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { AddApprovalRequest } from '@metamask/approval-controller';\nimport type {\n BaseConfig,\n BaseState,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport contractsMap from '@metamask/contract-metadata';\nimport {\n toChecksumHexAddress,\n ERC721_INTERFACE_ID,\n ORIGIN_METAMASK,\n ApprovalType,\n ERC20,\n} from '@metamask/controller-utils';\nimport { abiERC721 } from '@metamask/metamask-eth-abis';\nimport type {\n NetworkClientId,\n NetworkController,\n NetworkState,\n} from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { EventEmitter } from 'events';\nimport { v1 as random } from 'uuid';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport {\n formatAggregatorNames,\n formatIconUrlWithProxy,\n validateTokenToWatch,\n} from './assetsUtil';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from './token-service';\nimport type {\n TokenListMap,\n TokenListState,\n TokenListToken,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\n\n/**\n * @type TokensConfig\n *\n * Tokens controller configuration\n * @property selectedAddress - Vault selected address\n */\nexport interface TokensConfig extends BaseConfig {\n selectedAddress: string;\n chainId: Hex;\n provider: any;\n}\n\n/**\n * @type SuggestedAssetMeta\n *\n * Suggested asset by EIP747 meta data\n * @property id - Generated UUID associated with this suggested asset\n * @property time - Timestamp associated with this this suggested asset\n * @property type - Type type this suggested asset\n * @property asset - Asset suggested object\n * @property interactingAddress - Account address that requested watch asset\n */\ntype SuggestedAssetMeta = {\n id: string;\n time: number;\n type: string;\n asset: Token;\n interactingAddress: string;\n};\n\n/**\n * @type TokensState\n *\n * Assets controller state\n * @property tokens - List of tokens associated with the active network and address pair\n * @property ignoredTokens - List of ignoredTokens associated with the active network and address pair\n * @property detectedTokens - List of detected tokens associated with the active network and address pair\n * @property allTokens - Object containing tokens by network and account\n * @property allIgnoredTokens - Object containing hidden/ignored tokens by network and account\n * @property allDetectedTokens - Object containing tokens detected with non-zero balances\n */\nexport interface TokensState extends BaseState {\n tokens: Token[];\n ignoredTokens: string[];\n detectedTokens: Token[];\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allIgnoredTokens: { [chainId: Hex]: { [key: string]: string[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n}\n\n/**\n * The name of the {@link TokensController}.\n */\nconst controllerName = 'TokensController';\n\n/**\n * The external actions available to the {@link TokensController}.\n */\ntype AllowedActions = AddApprovalRequest;\n\n/**\n * The messenger of the {@link TokensController}.\n */\nexport type TokensControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n AllowedActions,\n never,\n AllowedActions['type'],\n never\n>;\n\n/**\n * Controller that stores assets and exposes convenience methods\n */\nexport class TokensController extends BaseController<\n TokensConfig,\n TokensState\n> {\n private readonly mutex = new Mutex();\n\n private abortController: AbortController;\n\n private readonly messagingSystem: TokensControllerMessenger;\n\n /**\n * Fetch metadata for a token.\n *\n * @param tokenAddress - The address of the token.\n * @returns The token metadata.\n */\n private async fetchTokenMetadata(\n tokenAddress: string,\n ): Promise<TokenListToken | undefined> {\n try {\n const token = await fetchTokenMetadata<TokenListToken>(\n this.config.chainId,\n tokenAddress,\n this.abortController.signal,\n );\n return token;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * EventEmitter instance used to listen to specific EIP747 events\n */\n hub = new EventEmitter();\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokensController';\n\n private readonly getERC20TokenName: AssetsContractController['getERC20TokenName'];\n\n private readonly getNetworkClientById: NetworkController['getNetworkClientById'];\n\n /**\n * Creates a TokensController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.\n * @param options.getERC20TokenName - Gets the ERC-20 token name.\n * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.\n * @param options.config - Initial options used to configure this controller.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messenger.\n */\n constructor({\n chainId: initialChainId,\n onPreferencesStateChange,\n onNetworkStateChange,\n onTokenListStateChange,\n getERC20TokenName,\n getNetworkClientById,\n config,\n state,\n messenger,\n }: {\n chainId: Hex;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n onTokenListStateChange: (\n listener: (tokenListState: TokenListState) => void,\n ) => void;\n getERC20TokenName: AssetsContractController['getERC20TokenName'];\n getNetworkClientById: NetworkController['getNetworkClientById'];\n config?: Partial<TokensConfig>;\n state?: Partial<TokensState>;\n messenger: TokensControllerMessenger;\n }) {\n super(config, state);\n\n this.defaultConfig = {\n selectedAddress: '',\n chainId: initialChainId,\n provider: undefined,\n ...config,\n };\n\n this.defaultState = {\n tokens: [],\n ignoredTokens: [],\n detectedTokens: [],\n allTokens: {},\n allIgnoredTokens: {},\n allDetectedTokens: {},\n ...state,\n };\n\n this.initialize();\n this.abortController = new AbortController();\n this.getERC20TokenName = getERC20TokenName;\n this.getNetworkClientById = getNetworkClientById;\n\n this.messagingSystem = messenger;\n\n onPreferencesStateChange(({ selectedAddress }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = this.config;\n this.configure({ selectedAddress });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onNetworkStateChange(({ providerConfig }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { selectedAddress } = this.config;\n const { chainId } = providerConfig;\n this.abortController.abort();\n this.abortController = new AbortController();\n this.configure({ chainId });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onTokenListStateChange(({ tokenList }) => {\n const { tokens } = this.state;\n if (tokens.length && !tokens[0].name) {\n this.updateTokensAttribute(tokenList, 'name');\n }\n });\n }\n\n /**\n * Adds a token to the stored token list.\n *\n * @param options - The method argument object.\n * @param options.address - Hex address of the token contract.\n * @param options.symbol - Symbol of the token.\n * @param options.decimals - Number of decimals the token uses.\n * @param options.name - Name of the token.\n * @param options.image - Image of the token.\n * @param options.interactingAddress - The address of the account to add a token to.\n * @param options.networkClientId - Network Client ID.\n * @returns Current token list.\n */\n async addToken({\n address,\n symbol,\n decimals,\n name,\n image,\n interactingAddress,\n networkClientId,\n }: {\n address: string;\n symbol: string;\n decimals: number;\n name?: string;\n image?: string;\n interactingAddress?: string;\n networkClientId?: NetworkClientId;\n }): Promise<Token[]> {\n const { chainId, selectedAddress } = 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 =\n this.getNetworkClientById(networkClientId).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.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 =\n this.getNetworkClientById(networkClientId).configuration.chainId;\n }\n\n const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } =\n this._getNewAllTokensState({\n newTokens,\n newDetectedTokens,\n newIgnoredTokens,\n interactingChainId,\n });\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n ignoredTokens: newIgnoredTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Ignore a batch of tokens.\n *\n * @param tokenAddressesToIgnore - Array of token addresses to ignore.\n */\n ignoreTokens(tokenAddressesToIgnore: string[]) {\n const { ignoredTokens, detectedTokens, tokens } = this.state;\n const ignoredTokensMap: { [key: string]: true } = {};\n let newIgnoredTokens: string[] = [...ignoredTokens];\n\n const checksummedTokenAddresses = tokenAddressesToIgnore.map((address) => {\n const checksumAddress = toChecksumHexAddress(address);\n ignoredTokensMap[address.toLowerCase()] = true;\n return checksumAddress;\n });\n newIgnoredTokens = [...ignoredTokens, ...checksummedTokenAddresses];\n const newDetectedTokens = detectedTokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n const newTokens = tokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n\n const { newAllIgnoredTokens, newAllDetectedTokens, newAllTokens } =\n this._getNewAllTokensState({\n newIgnoredTokens,\n newDetectedTokens,\n newTokens,\n });\n\n this.update({\n ignoredTokens: newIgnoredTokens,\n tokens: newTokens,\n detectedTokens: newDetectedTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n allTokens: newAllTokens,\n });\n }\n\n /**\n * Adds a batch of detected tokens to the stored token list.\n *\n * @param incomingDetectedTokens - Array of detected tokens to be added or updated.\n * @param detectionDetails - An object containing the chain ID and address of the currently selected network on which the incomingDetectedTokens were detected.\n * @param detectionDetails.selectedAddress - the account address on which the incomingDetectedTokens were detected.\n * @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.\n */\n async addDetectedTokens(\n incomingDetectedTokens: Token[],\n detectionDetails?: { selectedAddress: string; chainId: Hex },\n ) {\n const releaseLock = await this.mutex.acquire();\n\n // Get existing tokens for the chain + account\n const chainId = detectionDetails?.chainId ?? this.config.chainId;\n const accountAddress =\n detectionDetails?.selectedAddress ?? this.config.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 const { chainId: currentChain, selectedAddress: currentAddress } =\n this.config;\n\n newTokens = newAllTokens?.[currentChain]?.[currentAddress] || [];\n newDetectedTokens =\n newAllDetectedTokens?.[currentChain]?.[currentAddress] || [];\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Adds isERC721 field to token object. This is called when a user attempts to add tokens that\n * were previously added which do not yet had isERC721 field.\n *\n * @param tokenAddress - The contract address of the token requiring the isERC721 field added.\n * @returns The new token object with the added isERC721 field.\n */\n async updateTokenType(tokenAddress: string) {\n const isERC721 = await this._detectIsERC721(tokenAddress);\n const { tokens } = this.state;\n const tokenIndex = tokens.findIndex((token) => {\n return token.address.toLowerCase() === tokenAddress.toLowerCase();\n });\n tokens[tokenIndex].isERC721 = isERC721;\n this.update({ tokens });\n return tokens[tokenIndex];\n }\n\n /**\n * This is a function that updates the tokens name for the tokens name if it is not defined.\n *\n * @param tokenList - Represents the fetched token list from service API\n * @param tokenAttribute - Represents the token attribute that we want to update on the token list\n */\n private updateTokensAttribute(\n tokenList: TokenListMap,\n tokenAttribute: keyof Token & keyof TokenListToken,\n ) {\n const { tokens } = this.state;\n\n const newTokens = tokens.map((token) => {\n const newToken = tokenList[token.address.toLowerCase()];\n\n return !token[tokenAttribute] && newToken?.[tokenAttribute]\n ? { ...token, [tokenAttribute]: newToken[tokenAttribute] }\n : { ...token };\n });\n\n this.update({ tokens: newTokens });\n }\n\n /**\n * Detects whether or not a token is ERC-721 compatible.\n *\n * @param tokenAddress - The token contract address.\n * @param networkClientId - Optional network client ID to fetch contract info with.\n * @returns A boolean indicating whether the token address passed in supports the EIP-721\n * interface.\n */\n async _detectIsERC721(\n tokenAddress: string,\n networkClientId?: NetworkClientId,\n ) {\n const checksumAddress = toChecksumHexAddress(tokenAddress);\n // if this token is already in our contract metadata map we don't need\n // to check against the contract\n if (contractsMap[checksumAddress]?.erc721 === true) {\n return Promise.resolve(true);\n } else if (contractsMap[checksumAddress]?.erc20 === true) {\n return Promise.resolve(false);\n }\n\n const tokenContract = this._createEthersContract(\n tokenAddress,\n abiERC721,\n networkClientId,\n );\n try {\n return await tokenContract.supportsInterface(ERC721_INTERFACE_ID);\n } catch (error: any) {\n // currently we see a variety of errors across different networks when\n // token contracts are not ERC721 compatible. We need to figure out a better\n // way of differentiating token interface types but for now if we get an error\n // we have to assume the token is not ERC721 compatible.\n return false;\n }\n }\n\n _createEthersContract(\n tokenAddress: string,\n abi: string,\n networkClientId?: NetworkClientId,\n ): Contract {\n const provider = networkClientId\n ? this.getNetworkClientById(networkClientId).provider\n : this.config?.provider;\n\n const web3provider = new Web3Provider(provider);\n const tokenContract = new Contract(tokenAddress, abi, web3provider);\n return tokenContract;\n }\n\n _generateRandomId(): string {\n return random();\n }\n\n /**\n * Adds a new suggestedAsset to the list of watched assets.\n * Parameters will be validated according to the asset type being watched.\n *\n * @param options - The method options.\n * @param options.asset - The asset to be watched. For now only ERC20 tokens are accepted.\n * @param options.type - The asset type.\n * @param options.interactingAddress - The address of the account that is requesting to watch the asset.\n * @param options.networkClientId - Network Client ID.\n * @returns Object containing a Promise resolving to the suggestedAsset address if accepted.\n */\n async watchAsset({\n asset,\n type,\n interactingAddress,\n networkClientId,\n }: {\n asset: Token;\n type: string;\n interactingAddress?: string;\n networkClientId?: NetworkClientId;\n }): Promise<void> {\n if (type !== ERC20) {\n throw new Error(`Asset of type ${type} not supported`);\n }\n\n const { selectedAddress } = this.config;\n\n const suggestedAssetMeta: SuggestedAssetMeta = {\n asset,\n id: this._generateRandomId(),\n time: Date.now(),\n type,\n interactingAddress: interactingAddress || selectedAddress,\n };\n\n validateTokenToWatch(asset);\n\n await this._requestApproval(suggestedAssetMeta);\n\n let name;\n try {\n name = await this.getERC20TokenName(asset.address, networkClientId);\n } catch (error) {\n name = undefined;\n }\n\n const { address, symbol, decimals, image } = asset;\n await this.addToken({\n address,\n symbol,\n decimals,\n name,\n image,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n networkClientId,\n });\n }\n\n /**\n * Takes a new tokens and ignoredTokens array for the current network/account combination\n * and returns new allTokens and allIgnoredTokens state to update to.\n *\n * @param params - Object that holds token params.\n * @param params.newTokens - The new tokens to set for the current network and selected account.\n * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.\n * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.\n * @param params.interactingAddress - The account address to use to store the tokens.\n * @param params.interactingChainId - The chainId to use to store the tokens.\n * @returns The updated `allTokens` and `allIgnoredTokens` state.\n */\n _getNewAllTokensState(params: {\n newTokens?: Token[];\n newIgnoredTokens?: string[];\n newDetectedTokens?: Token[];\n interactingAddress?: string;\n interactingChainId?: Hex;\n }) {\n const {\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n interactingAddress,\n interactingChainId,\n } = params;\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId, selectedAddress } = this.config;\n\n const userAddressToAddTokens = interactingAddress ?? selectedAddress;\n const chainIdToAddTokens = interactingChainId ?? chainId;\n\n let newAllTokens = allTokens;\n if (\n newTokens?.length ||\n (newTokens &&\n allTokens &&\n allTokens[chainIdToAddTokens] &&\n allTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkTokens = allTokens[chainIdToAddTokens];\n const newNetworkTokens = {\n ...networkTokens,\n ...{ [userAddressToAddTokens]: newTokens },\n };\n newAllTokens = {\n ...allTokens,\n ...{ [chainIdToAddTokens]: newNetworkTokens },\n };\n }\n\n let newAllIgnoredTokens = allIgnoredTokens;\n if (\n newIgnoredTokens?.length ||\n (newIgnoredTokens &&\n allIgnoredTokens &&\n allIgnoredTokens[chainIdToAddTokens] &&\n allIgnoredTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkIgnoredTokens = allIgnoredTokens[chainIdToAddTokens];\n const newIgnoredNetworkTokens = {\n ...networkIgnoredTokens,\n ...{ [userAddressToAddTokens]: newIgnoredTokens },\n };\n newAllIgnoredTokens = {\n ...allIgnoredTokens,\n ...{ [chainIdToAddTokens]: newIgnoredNetworkTokens },\n };\n }\n\n let newAllDetectedTokens = allDetectedTokens;\n if (\n newDetectedTokens?.length ||\n (newDetectedTokens &&\n allDetectedTokens &&\n allDetectedTokens[chainIdToAddTokens] &&\n allDetectedTokens[chainIdToAddTokens][userAddressToAddTokens])\n ) {\n const networkDetectedTokens = allDetectedTokens[chainIdToAddTokens];\n const newDetectedNetworkTokens = {\n ...networkDetectedTokens,\n ...{ [userAddressToAddTokens]: newDetectedTokens },\n };\n newAllDetectedTokens = {\n ...allDetectedTokens,\n ...{ [chainIdToAddTokens]: newDetectedNetworkTokens },\n };\n }\n return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };\n }\n\n /**\n * Removes all tokens from the ignored list.\n */\n clearIgnoredTokens() {\n this.update({ ignoredTokens: [], allIgnoredTokens: {} });\n }\n\n async _requestApproval(suggestedAssetMeta: SuggestedAssetMeta) {\n return this.messagingSystem.call(\n 'ApprovalController:addRequest',\n {\n id: suggestedAssetMeta.id,\n origin: ORIGIN_METAMASK,\n type: ApprovalType.WatchAsset,\n requestData: {\n id: suggestedAssetMeta.id,\n interactingAddress: suggestedAssetMeta.interactingAddress,\n asset: {\n address: suggestedAssetMeta.asset.address,\n decimals: suggestedAssetMeta.asset.decimals,\n symbol: suggestedAssetMeta.asset.symbol,\n image: suggestedAssetMeta.asset.image || null,\n },\n },\n },\n true,\n );\n }\n}\n\nexport default TokensController;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/assets-controllers",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "17.0.0-preview.7f750b2",
|
|
4
4
|
"description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MetaMask",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"@ethersproject/contracts": "^5.7.0",
|
|
35
35
|
"@ethersproject/providers": "^5.7.0",
|
|
36
36
|
"@metamask/abi-utils": "^2.0.2",
|
|
37
|
-
"@metamask/approval-controller": "^4.0
|
|
37
|
+
"@metamask/approval-controller": "^4.1.0",
|
|
38
38
|
"@metamask/base-controller": "^3.2.3",
|
|
39
39
|
"@metamask/contract-metadata": "^2.3.1",
|
|
40
40
|
"@metamask/controller-utils": "^5.0.2",
|
|
41
41
|
"@metamask/eth-query": "^3.0.1",
|
|
42
42
|
"@metamask/metamask-eth-abis": "3.0.0",
|
|
43
|
-
"@metamask/network-controller": "^15.
|
|
44
|
-
"@metamask/polling-controller": "^0.
|
|
43
|
+
"@metamask/network-controller": "^15.1.0",
|
|
44
|
+
"@metamask/polling-controller": "^1.0.0",
|
|
45
45
|
"@metamask/preferences-controller": "^4.4.3",
|
|
46
46
|
"@metamask/rpc-errors": "^6.1.0",
|
|
47
47
|
"@metamask/utils": "^8.1.0",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"uuid": "^8.3.2"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@metamask/auto-changelog": "^3.4.
|
|
57
|
+
"@metamask/auto-changelog": "^3.4.2",
|
|
58
58
|
"@types/jest": "^27.4.1",
|
|
59
59
|
"@types/node": "^16.18.54",
|
|
60
60
|
"deepmerge": "^4.2.2",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"typescript": "~4.8.4"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"@metamask/approval-controller": "^4.0
|
|
73
|
-
"@metamask/network-controller": "^15.
|
|
72
|
+
"@metamask/approval-controller": "^4.1.0",
|
|
73
|
+
"@metamask/network-controller": "^15.1.0",
|
|
74
74
|
"@metamask/preferences-controller": "^4.4.3"
|
|
75
75
|
},
|
|
76
76
|
"engines": {
|