@metamask-previews/assets-controllers 20.0.0-preview.3fbb6b41 → 23.1.0-preview.353ee83b
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 +103 -10
- package/dist/AccountTrackerController.d.ts +28 -7
- package/dist/AccountTrackerController.d.ts.map +1 -1
- package/dist/AccountTrackerController.js +104 -30
- package/dist/AccountTrackerController.js.map +1 -1
- package/dist/AssetsContractController.d.ts.map +1 -1
- package/dist/AssetsContractController.js +4 -0
- package/dist/AssetsContractController.js.map +1 -1
- package/dist/CurrencyRateController.d.ts +2 -2
- package/dist/CurrencyRateController.d.ts.map +1 -1
- package/dist/CurrencyRateController.js +1 -1
- package/dist/CurrencyRateController.js.map +1 -1
- package/dist/NftController.d.ts +75 -1
- package/dist/NftController.d.ts.map +1 -1
- package/dist/NftController.js +35 -14
- package/dist/NftController.js.map +1 -1
- package/dist/NftDetectionController.d.ts +7 -4
- package/dist/NftDetectionController.d.ts.map +1 -1
- package/dist/NftDetectionController.js +26 -14
- package/dist/NftDetectionController.js.map +1 -1
- package/dist/Standards/ERC20Standard.d.ts.map +1 -1
- package/dist/Standards/ERC20Standard.js +4 -0
- package/dist/Standards/ERC20Standard.js.map +1 -1
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts +11 -10
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts.map +1 -1
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js +106 -85
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js.map +1 -1
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.d.ts.map +1 -1
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.js +2 -0
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.js.map +1 -1
- package/dist/Standards/standards-types.d.ts.map +1 -1
- package/dist/Standards/standards-types.js.map +1 -1
- package/dist/TokenDetectionController.d.ts +43 -56
- package/dist/TokenDetectionController.d.ts.map +1 -1
- package/dist/TokenDetectionController.js +132 -96
- package/dist/TokenDetectionController.js.map +1 -1
- package/dist/TokenListController.d.ts +6 -4
- package/dist/TokenListController.d.ts.map +1 -1
- package/dist/TokenListController.js +11 -10
- package/dist/TokenListController.js.map +1 -1
- package/dist/TokenRatesController.d.ts +6 -38
- package/dist/TokenRatesController.d.ts.map +1 -1
- package/dist/TokenRatesController.js +125 -93
- package/dist/TokenRatesController.js.map +1 -1
- package/dist/TokensController.d.ts +5 -6
- package/dist/TokensController.d.ts.map +1 -1
- package/dist/TokensController.js +81 -21
- package/dist/TokensController.js.map +1 -1
- package/dist/assetsUtil.d.ts +80 -9
- package/dist/assetsUtil.d.ts.map +1 -1
- package/dist/assetsUtil.js +177 -27
- package/dist/assetsUtil.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/token-prices-service/abstract-token-prices-service.d.ts +15 -16
- package/dist/token-prices-service/abstract-token-prices-service.d.ts.map +1 -1
- package/dist/token-prices-service/abstract-token-prices-service.js.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.ts +61 -3
- package/dist/token-prices-service/codefi-v2.d.ts.map +1 -1
- package/dist/token-prices-service/codefi-v2.js +86 -20
- package/dist/token-prices-service/codefi-v2.js.map +1 -1
- package/dist/token-prices-service/index.d.ts +1 -1
- package/dist/token-prices-service/index.js +2 -2
- package/dist/token-prices-service/index.js.map +1 -1
- package/package.json +15 -11
|
@@ -19,11 +19,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
19
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
20
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
21
21
|
};
|
|
22
|
-
var _TokenRatesController_instances, _TokenRatesController_pollState, _TokenRatesController_tokenPricesService,
|
|
22
|
+
var _TokenRatesController_instances, _TokenRatesController_pollState, _TokenRatesController_tokenPricesService, _TokenRatesController_inProcessExchangeRateUpdates, _TokenRatesController_getTokenAddresses, _TokenRatesController_stopPoll, _TokenRatesController_poll, _TokenRatesController_fetchAndMapExchangeRates, _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency, _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency;
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
exports.TokenRatesController = void 0;
|
|
25
25
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
26
26
|
const polling_controller_1 = require("@metamask/polling-controller");
|
|
27
|
+
const lodash_1 = require("lodash");
|
|
28
|
+
const assetsUtil_1 = require("./assetsUtil");
|
|
27
29
|
const crypto_compare_1 = require("./crypto-compare");
|
|
28
30
|
var PollState;
|
|
29
31
|
(function (PollState) {
|
|
@@ -61,7 +63,7 @@ function getCurrencyConversionRate({ from, to, }) {
|
|
|
61
63
|
* Controller that passively polls on a set interval for token-to-fiat exchange rates
|
|
62
64
|
* for tokens stored in the TokensController
|
|
63
65
|
*/
|
|
64
|
-
class TokenRatesController extends polling_controller_1.
|
|
66
|
+
class TokenRatesController extends polling_controller_1.StaticIntervalPollingControllerV1 {
|
|
65
67
|
/**
|
|
66
68
|
* Creates a TokenRatesController instance.
|
|
67
69
|
*
|
|
@@ -82,9 +84,9 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
|
|
|
82
84
|
constructor({ interval = 3 * 60 * 1000, threshold = 6 * 60 * 60 * 1000, getNetworkClientById, chainId: initialChainId, ticker: initialTicker, selectedAddress: initialSelectedAddress, onPreferencesStateChange, onTokensStateChange, onNetworkStateChange, tokenPricesService, }, config, state) {
|
|
83
85
|
super(config, state);
|
|
84
86
|
_TokenRatesController_instances.add(this);
|
|
85
|
-
this.tokenList = [];
|
|
86
87
|
_TokenRatesController_pollState.set(this, PollState.Inactive);
|
|
87
88
|
_TokenRatesController_tokenPricesService.set(this, void 0);
|
|
89
|
+
_TokenRatesController_inProcessExchangeRateUpdates.set(this, {});
|
|
88
90
|
/**
|
|
89
91
|
* Name of this controller used during composition
|
|
90
92
|
*/
|
|
@@ -110,25 +112,21 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
|
|
|
110
112
|
if (config === null || config === void 0 ? void 0 : config.disabled) {
|
|
111
113
|
this.configure({ disabled: true }, false, false);
|
|
112
114
|
}
|
|
113
|
-
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
|
|
114
115
|
onPreferencesStateChange(({ selectedAddress }) => __awaiter(this, void 0, void 0, function* () {
|
|
115
116
|
if (this.config.selectedAddress !== selectedAddress) {
|
|
116
117
|
this.configure({ selectedAddress });
|
|
117
|
-
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
|
|
118
118
|
if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
|
|
119
119
|
yield this.updateExchangeRates();
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
}));
|
|
123
123
|
onTokensStateChange(({ allTokens, allDetectedTokens }) => __awaiter(this, void 0, void 0, function* () {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
__classPrivateFieldGet(this,
|
|
129
|
-
|
|
130
|
-
yield this.updateExchangeRates();
|
|
131
|
-
}
|
|
124
|
+
const previousTokenAddresses = __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_getTokenAddresses).call(this, this.config.chainId);
|
|
125
|
+
this.configure({ allTokens, allDetectedTokens });
|
|
126
|
+
const newTokenAddresses = __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_getTokenAddresses).call(this, this.config.chainId);
|
|
127
|
+
if (!(0, lodash_1.isEqual)(previousTokenAddresses, newTokenAddresses) &&
|
|
128
|
+
__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
|
|
129
|
+
yield this.updateExchangeRates();
|
|
132
130
|
}
|
|
133
131
|
}));
|
|
134
132
|
onNetworkStateChange(({ providerConfig }) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -137,7 +135,6 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
|
|
|
137
135
|
this.config.nativeCurrency !== ticker) {
|
|
138
136
|
this.update({ contractExchangeRates: {} });
|
|
139
137
|
this.configure({ chainId, nativeCurrency: ticker });
|
|
140
|
-
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
|
|
141
138
|
if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
|
|
142
139
|
yield this.updateExchangeRates();
|
|
143
140
|
}
|
|
@@ -166,18 +163,10 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
|
|
|
166
163
|
*/
|
|
167
164
|
updateExchangeRates() {
|
|
168
165
|
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
-
if (this.tokenList.length === 0 || this.disabled) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
166
|
const { chainId, nativeCurrency } = this.config;
|
|
173
|
-
const tokenContractAddresses = this.tokenList.map((token) => token.address);
|
|
174
167
|
yield this.updateExchangeRatesByChainId({
|
|
175
168
|
chainId,
|
|
176
169
|
nativeCurrency,
|
|
177
|
-
tokenContractAddresses,
|
|
178
|
-
});
|
|
179
|
-
this.update({
|
|
180
|
-
contractExchangeRates: this.state.contractExchangeRatesByChainId[chainId][nativeCurrency],
|
|
181
170
|
});
|
|
182
171
|
});
|
|
183
172
|
}
|
|
@@ -187,92 +176,80 @@ class TokenRatesController extends polling_controller_1.PollingControllerV1 {
|
|
|
187
176
|
* @param options - The options to fetch exchange rates.
|
|
188
177
|
* @param options.chainId - The chain ID.
|
|
189
178
|
* @param options.nativeCurrency - The ticker for the chain.
|
|
190
|
-
* @param options.tokenContractAddresses - The addresses for the token contracts.
|
|
191
179
|
*/
|
|
192
|
-
updateExchangeRatesByChainId({ chainId, nativeCurrency,
|
|
180
|
+
updateExchangeRatesByChainId({ chainId, nativeCurrency, }) {
|
|
193
181
|
var _a;
|
|
194
182
|
return __awaiter(this, void 0, void 0, function* () {
|
|
195
|
-
if (
|
|
183
|
+
if (this.disabled) {
|
|
196
184
|
return;
|
|
197
185
|
}
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Uses the token prices service to retrieve exchange rates for tokens in a
|
|
211
|
-
* particular currency.
|
|
212
|
-
*
|
|
213
|
-
* If the price API does not support the given chain ID, returns an empty
|
|
214
|
-
* object.
|
|
215
|
-
*
|
|
216
|
-
* If the price API does not support the given currency, retrieves exchange
|
|
217
|
-
* rates in a known currency instead, then converts those rates using the
|
|
218
|
-
* exchange rate between the known currency and desired currency.
|
|
219
|
-
*
|
|
220
|
-
* @param args - The arguments to this function.
|
|
221
|
-
* @param args.tokenContractAddresses - Contract addresses for tokens.
|
|
222
|
-
* @param args.chainId - The EIP-155 ID of the chain where the tokens live.
|
|
223
|
-
* @param args.nativeCurrency - The native currency in which to request
|
|
224
|
-
* exchange rates.
|
|
225
|
-
* @returns A map from token contract address to its exchange rate in the
|
|
226
|
-
* native currency, or an empty map if no exchange rates can be obtained for
|
|
227
|
-
* the chain ID.
|
|
228
|
-
*/
|
|
229
|
-
fetchAndMapExchangeRates({ tokenContractAddresses, chainId, nativeCurrency, }) {
|
|
230
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
-
if (!__classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").validateChainIdSupported(chainId)) {
|
|
232
|
-
return tokenContractAddresses.reduce((obj, tokenContractAddress) => {
|
|
233
|
-
return Object.assign(Object.assign({}, obj), { [tokenContractAddress]: undefined });
|
|
234
|
-
}, {});
|
|
186
|
+
const tokenAddresses = __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_getTokenAddresses).call(this, chainId);
|
|
187
|
+
if (tokenAddresses.length === 0) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const updateKey = `${chainId}:${nativeCurrency}`;
|
|
191
|
+
if (updateKey in __classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")) {
|
|
192
|
+
// This prevents redundant updates
|
|
193
|
+
// This promise is resolved after the in-progress update has finished,
|
|
194
|
+
// and state has been updated.
|
|
195
|
+
yield __classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")[updateKey];
|
|
196
|
+
return;
|
|
235
197
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
198
|
+
const { promise: inProgressUpdate, resolve: updateSucceeded, reject: updateFailed, } = createDeferredPromise({ suppressUnhandledRejection: true });
|
|
199
|
+
__classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")[updateKey] = inProgressUpdate;
|
|
200
|
+
try {
|
|
201
|
+
const newContractExchangeRates = yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRates).call(this, {
|
|
202
|
+
tokenAddresses,
|
|
239
203
|
chainId,
|
|
240
204
|
nativeCurrency,
|
|
241
205
|
});
|
|
206
|
+
const existingContractExchangeRates = this.state.contractExchangeRates;
|
|
207
|
+
const updatedContractExchangeRates = chainId === this.config.chainId &&
|
|
208
|
+
nativeCurrency === this.config.nativeCurrency
|
|
209
|
+
? newContractExchangeRates
|
|
210
|
+
: existingContractExchangeRates;
|
|
211
|
+
const existingContractExchangeRatesForChainId = (_a = this.state.contractExchangeRatesByChainId[chainId]) !== null && _a !== void 0 ? _a : {};
|
|
212
|
+
const updatedContractExchangeRatesForChainId = Object.assign(Object.assign({}, this.state.contractExchangeRatesByChainId), { [chainId]: Object.assign(Object.assign({}, existingContractExchangeRatesForChainId), { [nativeCurrency]: Object.assign(Object.assign({}, existingContractExchangeRatesForChainId[nativeCurrency]), newContractExchangeRates) }) });
|
|
213
|
+
this.update({
|
|
214
|
+
contractExchangeRates: updatedContractExchangeRates,
|
|
215
|
+
contractExchangeRatesByChainId: updatedContractExchangeRatesForChainId,
|
|
216
|
+
});
|
|
217
|
+
updateSucceeded();
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
updateFailed(error);
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
delete __classPrivateFieldGet(this, _TokenRatesController_inProcessExchangeRateUpdates, "f")[updateKey];
|
|
242
225
|
}
|
|
243
|
-
return yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency).call(this, {
|
|
244
|
-
tokenContractAddresses,
|
|
245
|
-
nativeCurrency,
|
|
246
|
-
});
|
|
247
226
|
});
|
|
248
227
|
}
|
|
249
228
|
/**
|
|
250
|
-
* Updates token rates for the given networkClientId
|
|
229
|
+
* Updates token rates for the given networkClientId
|
|
251
230
|
*
|
|
252
231
|
* @param networkClientId - The network client ID used to get a ticker value.
|
|
253
|
-
* @param options - The polling options.
|
|
254
|
-
* @param options.tokenAddresses - The addresses for the token contracts.
|
|
255
232
|
* @returns The controller state.
|
|
256
233
|
*/
|
|
257
|
-
_executePoll(networkClientId
|
|
234
|
+
_executePoll(networkClientId) {
|
|
258
235
|
return __awaiter(this, void 0, void 0, function* () {
|
|
259
236
|
const networkClient = this.getNetworkClientById(networkClientId);
|
|
260
237
|
yield this.updateExchangeRatesByChainId({
|
|
261
238
|
chainId: networkClient.configuration.chainId,
|
|
262
239
|
nativeCurrency: networkClient.configuration.ticker,
|
|
263
|
-
tokenContractAddresses: options.tokenAddresses,
|
|
264
240
|
});
|
|
265
241
|
});
|
|
266
242
|
}
|
|
267
243
|
}
|
|
268
244
|
exports.TokenRatesController = TokenRatesController;
|
|
269
|
-
_TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPricesService = new WeakMap(), _TokenRatesController_instances = new WeakSet(),
|
|
245
|
+
_TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPricesService = new WeakMap(), _TokenRatesController_inProcessExchangeRateUpdates = new WeakMap(), _TokenRatesController_instances = new WeakSet(), _TokenRatesController_getTokenAddresses = function _TokenRatesController_getTokenAddresses(chainId) {
|
|
270
246
|
var _a, _b;
|
|
271
247
|
const { allTokens, allDetectedTokens } = this.config;
|
|
272
|
-
const tokens = ((_a = allTokens[
|
|
273
|
-
const detectedTokens = ((_b = allDetectedTokens[
|
|
274
|
-
|
|
275
|
-
|
|
248
|
+
const tokens = ((_a = allTokens[chainId]) === null || _a === void 0 ? void 0 : _a[this.config.selectedAddress]) || [];
|
|
249
|
+
const detectedTokens = ((_b = allDetectedTokens[chainId]) === null || _b === void 0 ? void 0 : _b[this.config.selectedAddress]) || [];
|
|
250
|
+
return [
|
|
251
|
+
...new Set([...tokens, ...detectedTokens].map((token) => (0, controller_utils_1.toHex)((0, controller_utils_1.toChecksumHexAddress)(token.address)))),
|
|
252
|
+
].sort();
|
|
276
253
|
}, _TokenRatesController_stopPoll = function _TokenRatesController_stopPoll() {
|
|
277
254
|
if (this.handle) {
|
|
278
255
|
clearTimeout(this.handle);
|
|
@@ -286,24 +263,51 @@ _TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPric
|
|
|
286
263
|
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_poll).call(this);
|
|
287
264
|
}, this.config.interval);
|
|
288
265
|
});
|
|
289
|
-
},
|
|
266
|
+
}, _TokenRatesController_fetchAndMapExchangeRates = function _TokenRatesController_fetchAndMapExchangeRates({ tokenAddresses, chainId, nativeCurrency, }) {
|
|
267
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
268
|
+
if (!__classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").validateChainIdSupported(chainId)) {
|
|
269
|
+
return tokenAddresses.reduce((obj, tokenAddress) => {
|
|
270
|
+
return Object.assign(Object.assign({}, obj), { [tokenAddress]: undefined });
|
|
271
|
+
}, {});
|
|
272
|
+
}
|
|
273
|
+
if (__classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").validateCurrencySupported(nativeCurrency)) {
|
|
274
|
+
return yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency).call(this, {
|
|
275
|
+
tokenAddresses,
|
|
276
|
+
chainId,
|
|
277
|
+
nativeCurrency,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency).call(this, {
|
|
281
|
+
tokenAddresses,
|
|
282
|
+
nativeCurrency,
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
}, _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency = function _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency({ tokenAddresses, chainId, nativeCurrency, }) {
|
|
290
286
|
return __awaiter(this, void 0, void 0, function* () {
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
287
|
+
const tokenPricesByTokenAddress = yield (0, assetsUtil_1.reduceInBatchesSerially)({
|
|
288
|
+
values: tokenAddresses,
|
|
289
|
+
batchSize: assetsUtil_1.TOKEN_PRICES_BATCH_SIZE,
|
|
290
|
+
eachBatch: (allTokenPricesByTokenAddress, batch) => __awaiter(this, void 0, void 0, function* () {
|
|
291
|
+
const tokenPricesByTokenAddressForBatch = yield __classPrivateFieldGet(this, _TokenRatesController_tokenPricesService, "f").fetchTokenPrices({
|
|
292
|
+
tokenAddresses: batch,
|
|
293
|
+
chainId,
|
|
294
|
+
currency: nativeCurrency,
|
|
295
|
+
});
|
|
296
|
+
return Object.assign(Object.assign({}, allTokenPricesByTokenAddress), tokenPricesByTokenAddressForBatch);
|
|
297
|
+
}),
|
|
298
|
+
initialResult: {},
|
|
295
299
|
});
|
|
296
|
-
return Object.entries(
|
|
297
|
-
return Object.assign(Object.assign({}, obj), { [
|
|
300
|
+
return Object.entries(tokenPricesByTokenAddress).reduce((obj, [tokenAddress, tokenPrice]) => {
|
|
301
|
+
return Object.assign(Object.assign({}, obj), { [tokenAddress]: tokenPrice === null || tokenPrice === void 0 ? void 0 : tokenPrice.value });
|
|
298
302
|
}, {});
|
|
299
303
|
});
|
|
300
|
-
}, _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency = function _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency({
|
|
304
|
+
}, _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency = function _TokenRatesController_fetchAndMapExchangeRatesForUnsupportedNativeCurrency({ tokenAddresses, nativeCurrency, }) {
|
|
301
305
|
return __awaiter(this, void 0, void 0, function* () {
|
|
302
|
-
const [
|
|
303
|
-
__classPrivateFieldGet(this,
|
|
304
|
-
|
|
305
|
-
currency: controller_utils_1.FALL_BACK_VS_CURRENCY,
|
|
306
|
+
const [contractExchangeRates, fallbackCurrencyToNativeCurrencyConversionRate,] = yield Promise.all([
|
|
307
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeCurrency).call(this, {
|
|
308
|
+
tokenAddresses,
|
|
306
309
|
chainId: this.config.chainId,
|
|
310
|
+
nativeCurrency: controller_utils_1.FALL_BACK_VS_CURRENCY,
|
|
307
311
|
}),
|
|
308
312
|
getCurrencyConversionRate({
|
|
309
313
|
from: controller_utils_1.FALL_BACK_VS_CURRENCY,
|
|
@@ -313,10 +317,38 @@ _TokenRatesController_pollState = new WeakMap(), _TokenRatesController_tokenPric
|
|
|
313
317
|
if (fallbackCurrencyToNativeCurrencyConversionRate === null) {
|
|
314
318
|
return {};
|
|
315
319
|
}
|
|
316
|
-
return Object.entries(
|
|
317
|
-
return Object.assign(Object.assign({}, obj), { [
|
|
320
|
+
return Object.entries(contractExchangeRates).reduce((obj, [tokenAddress, tokenValue]) => {
|
|
321
|
+
return Object.assign(Object.assign({}, obj), { [tokenAddress]: tokenValue
|
|
322
|
+
? tokenValue * fallbackCurrencyToNativeCurrencyConversionRate
|
|
323
|
+
: undefined });
|
|
318
324
|
}, {});
|
|
319
325
|
});
|
|
320
326
|
};
|
|
327
|
+
/**
|
|
328
|
+
* Create a defered Promise.
|
|
329
|
+
*
|
|
330
|
+
* TODO: Migrate this to utils
|
|
331
|
+
*
|
|
332
|
+
* @param args - The arguments.
|
|
333
|
+
* @param args.suppressUnhandledRejection - This option adds an empty error handler
|
|
334
|
+
* to the Promise to suppress the UnhandledPromiseRejection error. This can be
|
|
335
|
+
* useful if the deferred Promise is sometimes intentionally not used.
|
|
336
|
+
* @returns A deferred Promise.
|
|
337
|
+
*/
|
|
338
|
+
function createDeferredPromise({ suppressUnhandledRejection = false, }) {
|
|
339
|
+
let resolve;
|
|
340
|
+
let reject;
|
|
341
|
+
const promise = new Promise((innerResolve, innerReject) => {
|
|
342
|
+
resolve = innerResolve;
|
|
343
|
+
reject = innerReject;
|
|
344
|
+
});
|
|
345
|
+
if (suppressUnhandledRejection) {
|
|
346
|
+
promise.catch((_error) => {
|
|
347
|
+
// This handler is used to suppress the UnhandledPromiseRejection error
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
// @ts-expect-error We know that these are assigned, but TypeScript doesn't
|
|
351
|
+
return { promise, resolve, reject };
|
|
352
|
+
}
|
|
321
353
|
exports.default = TokenRatesController;
|
|
322
354
|
//# sourceMappingURL=TokenRatesController.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenRatesController.js","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseConfig, BaseState } from '@metamask/base-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type {\n NetworkClientId,\n NetworkController,\n NetworkState,\n} from '@metamask/network-controller';\nimport { PollingControllerV1 } from '@metamask/polling-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport { fetchExchangeRate as fetchNativeCurrencyExchangeRate } from './crypto-compare';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport type { TokensState } from './TokensController';\n\n/**\n * @type Token\n *\n * Token representation\n * @property address - Hex address of the token contract\n * @property decimals - Number of decimals the token uses\n * @property symbol - Symbol of the token\n * @property image - Image of the token, url or bit32 image\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface Token {\n address: string;\n decimals: number;\n symbol: string;\n aggregators?: string[];\n image?: string;\n balanceError?: unknown;\n isERC721?: boolean;\n name?: string;\n}\n\n/**\n * @type TokenRatesConfig\n *\n * Token rates controller configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property nativeCurrency - Current native currency selected to use base of rates\n * @property chainId - Current network chainId\n * @property tokens - List of tokens to track exchange rates for\n * @property threshold - Threshold to invalidate the supportedChains\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesConfig extends BaseConfig {\n interval: number;\n nativeCurrency: string;\n chainId: Hex;\n selectedAddress: string;\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n threshold: number;\n}\n\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ninterface ContractExchangeRates {\n [address: string]: number | undefined;\n}\n\nenum PollState {\n Active = 'Active',\n Inactive = 'Inactive',\n}\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property contractExchangeRates - Hash of token contract addresses to exchange rates (single globally selected chain, will be deprecated soon)\n * @property contractExchangeRatesByChainId - Hash of token contract addresses to exchange rates keyed by chain ID and native currency (ticker)\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesState extends BaseState {\n contractExchangeRates: ContractExchangeRates;\n contractExchangeRatesByChainId: Record<\n Hex,\n Record<string, ContractExchangeRates>\n >;\n}\n\n/**\n * Uses the CryptoCompare API to fetch the exchange rate between one currency\n * and another, i.e., the multiplier to apply the amount of one currency in\n * order to convert it to another.\n *\n * @param args - The arguments to this function.\n * @param args.from - The currency to convert from.\n * @param args.to - The currency to convert to.\n * @returns The exchange rate between `fromCurrency` to `toCurrency` if one\n * exists, or null if one does not.\n */\nasync function getCurrencyConversionRate({\n from,\n to,\n}: {\n from: string;\n to: string;\n}) {\n const includeUSDRate = false;\n try {\n const result = await fetchNativeCurrencyExchangeRate(\n to,\n from,\n includeUSDRate,\n );\n return result.conversionRate;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Controller that passively polls on a set interval for token-to-fiat exchange rates\n * for tokens stored in the TokensController\n */\nexport class TokenRatesController extends PollingControllerV1<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n private tokenList: Token[] = [];\n\n #pollState = PollState.Inactive;\n\n #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenRatesController';\n\n private readonly getNetworkClientById: NetworkController['getNetworkClientById'];\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.interval - The polling interval in ms\n * @param options.threshold - The duration in ms before metadata fetched from CoinGecko is considered stale\n * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.\n * @param options.chainId - The chain ID of the current network.\n * @param options.ticker - The ticker for the current network.\n * @param options.selectedAddress - The current selected address.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onTokensStateChange - Allows subscribing to token controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network state changes.\n * @param options.tokenPricesService - An object in charge of retrieving token prices.\n * @param config - Initial options used to configure this controller.\n * @param state - Initial state to set on this controller.\n */\n constructor(\n {\n interval = 3 * 60 * 1000,\n threshold = 6 * 60 * 60 * 1000,\n getNetworkClientById,\n chainId: initialChainId,\n ticker: initialTicker,\n selectedAddress: initialSelectedAddress,\n onPreferencesStateChange,\n onTokensStateChange,\n onNetworkStateChange,\n tokenPricesService,\n }: {\n interval?: number;\n threshold?: number;\n getNetworkClientById: NetworkController['getNetworkClientById'];\n chainId: Hex;\n ticker: string;\n selectedAddress: string;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onTokensStateChange: (\n listener: (tokensState: TokensState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n tokenPricesService: AbstractTokenPricesService;\n },\n config?: Partial<TokenRatesConfig>,\n state?: Partial<TokenRatesState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n interval,\n threshold,\n disabled: false,\n nativeCurrency: initialTicker,\n chainId: initialChainId,\n selectedAddress: initialSelectedAddress,\n allTokens: {}, // TODO: initialize these correctly, maybe as part of BaseControllerV2 migration\n allDetectedTokens: {},\n };\n\n this.defaultState = {\n contractExchangeRates: {},\n contractExchangeRatesByChainId: {},\n };\n this.initialize();\n this.setIntervalLength(interval);\n this.getNetworkClientById = getNetworkClientById;\n this.#tokenPricesService = tokenPricesService;\n\n if (config?.disabled) {\n this.configure({ disabled: true }, false, false);\n }\n this.#updateTokenList();\n\n onPreferencesStateChange(async ({ selectedAddress }) => {\n if (this.config.selectedAddress !== selectedAddress) {\n this.configure({ selectedAddress });\n this.#updateTokenList();\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n\n onTokensStateChange(async ({ allTokens, allDetectedTokens }) => {\n // These two state properties are assumed to be immutable\n if (\n this.config.allTokens !== allTokens ||\n this.config.allDetectedTokens !== allDetectedTokens\n ) {\n this.configure({ allTokens, allDetectedTokens });\n this.#updateTokenList();\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n\n onNetworkStateChange(async ({ providerConfig }) => {\n const { chainId, ticker } = providerConfig;\n if (\n this.config.chainId !== chainId ||\n this.config.nativeCurrency !== ticker\n ) {\n this.update({ contractExchangeRates: {} });\n this.configure({ chainId, nativeCurrency: ticker });\n this.#updateTokenList();\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n }\n\n #updateTokenList() {\n const { allTokens, allDetectedTokens } = this.config;\n const tokens =\n allTokens[this.config.chainId]?.[this.config.selectedAddress] || [];\n const detectedTokens =\n allDetectedTokens[this.config.chainId]?.[this.config.selectedAddress] ||\n [];\n this.tokenList = [...tokens, ...detectedTokens];\n }\n\n /**\n * Start (or restart) polling.\n */\n async start() {\n this.#stopPoll();\n this.#pollState = PollState.Active;\n await this.#poll();\n }\n\n /**\n * Stop polling.\n */\n stop() {\n this.#stopPoll();\n this.#pollState = PollState.Inactive;\n }\n\n /**\n * Clear the active polling timer, if present.\n */\n #stopPoll() {\n if (this.handle) {\n clearTimeout(this.handle);\n }\n }\n\n /**\n * Poll for exchange rate updates.\n */\n async #poll() {\n await safelyExecute(() => this.updateExchangeRates());\n\n // Poll using recursive `setTimeout` instead of `setInterval` so that\n // requests don't stack if they take longer than the polling interval\n this.handle = setTimeout(() => {\n this.#poll();\n }, this.config.interval);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n if (this.tokenList.length === 0 || this.disabled) {\n return;\n }\n\n const { chainId, nativeCurrency } = this.config;\n const tokenContractAddresses = this.tokenList.map(\n (token) => token.address,\n ) as Hex[];\n await this.updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n tokenContractAddresses,\n });\n\n this.update({\n contractExchangeRates:\n this.state.contractExchangeRatesByChainId[chainId][nativeCurrency],\n });\n }\n\n /**\n * Updates exchange rates for all tokens.\n *\n * @param options - The options to fetch exchange rates.\n * @param options.chainId - The chain ID.\n * @param options.nativeCurrency - The ticker for the chain.\n * @param options.tokenContractAddresses - The addresses for the token contracts.\n */\n async updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n tokenContractAddresses,\n }: {\n chainId: Hex;\n nativeCurrency: string;\n tokenContractAddresses: Hex[];\n }) {\n if (tokenContractAddresses.length === 0 || this.disabled) {\n return;\n }\n\n const newContractExchangeRates = await this.fetchAndMapExchangeRates({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n });\n\n const existingContractExchangeRatesForChainId =\n this.state.contractExchangeRatesByChainId[chainId] ?? {};\n\n this.update({\n contractExchangeRatesByChainId: {\n ...this.state.contractExchangeRatesByChainId,\n [chainId]: {\n ...existingContractExchangeRatesForChainId,\n [nativeCurrency]: {\n ...existingContractExchangeRatesForChainId[nativeCurrency],\n ...newContractExchangeRates,\n },\n },\n },\n });\n }\n\n /**\n * Uses the token prices service to retrieve exchange rates for tokens in a\n * particular currency.\n *\n * If the price API does not support the given chain ID, returns an empty\n * object.\n *\n * If the price API does not support the given currency, retrieves exchange\n * rates in a known currency instead, then converts those rates using the\n * exchange rate between the known currency and desired currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenContractAddresses - Contract addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * exchange rates.\n * @returns A map from token contract address to its exchange rate in the\n * native currency, or an empty map if no exchange rates can be obtained for\n * the chain ID.\n */\n async fetchAndMapExchangeRates({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenContractAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n if (!this.#tokenPricesService.validateChainIdSupported(chainId)) {\n return tokenContractAddresses.reduce((obj, tokenContractAddress) => {\n return {\n ...obj,\n [tokenContractAddress]: undefined,\n };\n }, {});\n }\n\n if (this.#tokenPricesService.validateCurrencySupported(nativeCurrency)) {\n return await this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n });\n }\n\n return await this.#fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenContractAddresses,\n nativeCurrency,\n });\n }\n\n /**\n * Updates token rates for the given networkClientId and contract addresses\n *\n * @param networkClientId - The network client ID used to get a ticker value.\n * @param options - The polling options.\n * @param options.tokenAddresses - The addresses for the token contracts.\n * @returns The controller state.\n */\n async _executePoll(\n networkClientId: NetworkClientId,\n options: { tokenAddresses: Hex[] },\n ): Promise<void> {\n const networkClient = this.getNetworkClientById(networkClientId);\n await this.updateExchangeRatesByChainId({\n chainId: networkClient.configuration.chainId,\n nativeCurrency: networkClient.configuration.ticker,\n tokenContractAddresses: options.tokenAddresses,\n });\n }\n\n /**\n * Retrieves prices in the given currency for the given tokens on the given\n * chain. Ensures that token addresses are checksum addresses.\n *\n * @param args - The arguments to this function.\n * @param args.tokenContractAddresses - Contract addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenContractAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenContractAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const tokenPricesByTokenContractAddress =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenContractAddresses,\n chainId,\n currency: nativeCurrency,\n });\n\n return Object.entries(tokenPricesByTokenContractAddress).reduce(\n (obj, [tokenContractAddress, tokenPrice]) => {\n return {\n ...obj,\n [toChecksumHexAddress(tokenContractAddress)]: tokenPrice.value,\n };\n },\n {},\n );\n }\n\n /**\n * If the price API does not support a given native currency, then we need to\n * convert it to a fallback currency and feed that currency into the price\n * API, then convert the prices to our desired native currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenContractAddresses - The contract addresses for the tokens you\n * want to retrieve prices for.\n * @param args.nativeCurrency - The currency you want the prices to be in.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenContractAddresses,\n nativeCurrency,\n }: {\n tokenContractAddresses: Hex[];\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const [\n tokenPricesByTokenContractAddress,\n fallbackCurrencyToNativeCurrencyConversionRate,\n ] = await Promise.all([\n this.#tokenPricesService.fetchTokenPrices({\n tokenContractAddresses,\n currency: FALL_BACK_VS_CURRENCY,\n chainId: this.config.chainId,\n }),\n getCurrencyConversionRate({\n from: FALL_BACK_VS_CURRENCY,\n to: nativeCurrency,\n }),\n ]);\n\n if (fallbackCurrencyToNativeCurrencyConversionRate === null) {\n return {};\n }\n\n return Object.entries(tokenPricesByTokenContractAddress).reduce(\n (obj, [tokenContractAddress, tokenPrice]) => {\n return {\n ...obj,\n [toChecksumHexAddress(tokenContractAddress)]:\n tokenPrice.value * fallbackCurrencyToNativeCurrencyConversionRate,\n };\n },\n {},\n );\n }\n}\n\nexport default TokenRatesController;\n"]}
|
|
1
|
+
{"version":3,"file":"TokenRatesController.js","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseConfig, BaseState } from '@metamask/base-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n toHex,\n} from '@metamask/controller-utils';\nimport type {\n NetworkClientId,\n NetworkController,\n NetworkState,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingControllerV1 } from '@metamask/polling-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { isEqual } from 'lodash';\n\nimport { reduceInBatchesSerially, TOKEN_PRICES_BATCH_SIZE } from './assetsUtil';\nimport { fetchExchangeRate as fetchNativeCurrencyExchangeRate } from './crypto-compare';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport type { TokensState } from './TokensController';\n\n/**\n * @type Token\n *\n * Token representation\n * @property address - Hex address of the token contract\n * @property decimals - Number of decimals the token uses\n * @property symbol - Symbol of the token\n * @property image - Image of the token, url or bit32 image\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface Token {\n address: string;\n decimals: number;\n symbol: string;\n aggregators?: string[];\n image?: string;\n balanceError?: unknown;\n isERC721?: boolean;\n name?: string;\n}\n\n/**\n * @type TokenRatesConfig\n *\n * Token rates controller configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property nativeCurrency - Current native currency selected to use base of rates\n * @property chainId - Current network chainId\n * @property tokens - List of tokens to track exchange rates for\n * @property threshold - Threshold to invalidate the supportedChains\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesConfig extends BaseConfig {\n interval: number;\n nativeCurrency: string;\n chainId: Hex;\n selectedAddress: string;\n allTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } };\n threshold: number;\n}\n\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface ContractExchangeRates {\n [address: string]: number | undefined;\n}\n\nenum PollState {\n Active = 'Active',\n Inactive = 'Inactive',\n}\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property contractExchangeRates - Hash of token contract addresses to exchange rates (single globally selected chain, will be deprecated soon)\n * @property contractExchangeRatesByChainId - Hash of token contract addresses to exchange rates keyed by chain ID and native currency (ticker)\n */\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface TokenRatesState extends BaseState {\n contractExchangeRates: ContractExchangeRates;\n contractExchangeRatesByChainId: Record<\n Hex,\n Record<string, ContractExchangeRates>\n >;\n}\n\n/**\n * Uses the CryptoCompare API to fetch the exchange rate between one currency\n * and another, i.e., the multiplier to apply the amount of one currency in\n * order to convert it to another.\n *\n * @param args - The arguments to this function.\n * @param args.from - The currency to convert from.\n * @param args.to - The currency to convert to.\n * @returns The exchange rate between `fromCurrency` to `toCurrency` if one\n * exists, or null if one does not.\n */\nasync function getCurrencyConversionRate({\n from,\n to,\n}: {\n from: string;\n to: string;\n}) {\n const includeUSDRate = false;\n try {\n const result = await fetchNativeCurrencyExchangeRate(\n to,\n from,\n includeUSDRate,\n );\n return result.conversionRate;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Controller that passively polls on a set interval for token-to-fiat exchange rates\n * for tokens stored in the TokensController\n */\nexport class TokenRatesController extends StaticIntervalPollingControllerV1<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n #pollState = PollState.Inactive;\n\n #tokenPricesService: AbstractTokenPricesService;\n\n #inProcessExchangeRateUpdates: Record<`${Hex}:${string}`, Promise<void>> = {};\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenRatesController';\n\n private readonly getNetworkClientById: NetworkController['getNetworkClientById'];\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.interval - The polling interval in ms\n * @param options.threshold - The duration in ms before metadata fetched from CoinGecko is considered stale\n * @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.\n * @param options.chainId - The chain ID of the current network.\n * @param options.ticker - The ticker for the current network.\n * @param options.selectedAddress - The current selected address.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onTokensStateChange - Allows subscribing to token controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network state changes.\n * @param options.tokenPricesService - An object in charge of retrieving token prices.\n * @param config - Initial options used to configure this controller.\n * @param state - Initial state to set on this controller.\n */\n constructor(\n {\n interval = 3 * 60 * 1000,\n threshold = 6 * 60 * 60 * 1000,\n getNetworkClientById,\n chainId: initialChainId,\n ticker: initialTicker,\n selectedAddress: initialSelectedAddress,\n onPreferencesStateChange,\n onTokensStateChange,\n onNetworkStateChange,\n tokenPricesService,\n }: {\n interval?: number;\n threshold?: number;\n getNetworkClientById: NetworkController['getNetworkClientById'];\n chainId: Hex;\n ticker: string;\n selectedAddress: string;\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onTokensStateChange: (\n listener: (tokensState: TokensState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n tokenPricesService: AbstractTokenPricesService;\n },\n config?: Partial<TokenRatesConfig>,\n state?: Partial<TokenRatesState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n interval,\n threshold,\n disabled: false,\n nativeCurrency: initialTicker,\n chainId: initialChainId,\n selectedAddress: initialSelectedAddress,\n allTokens: {}, // TODO: initialize these correctly, maybe as part of BaseControllerV2 migration\n allDetectedTokens: {},\n };\n\n this.defaultState = {\n contractExchangeRates: {},\n contractExchangeRatesByChainId: {},\n };\n this.initialize();\n this.setIntervalLength(interval);\n this.getNetworkClientById = getNetworkClientById;\n this.#tokenPricesService = tokenPricesService;\n\n if (config?.disabled) {\n this.configure({ disabled: true }, false, false);\n }\n\n onPreferencesStateChange(async ({ selectedAddress }) => {\n if (this.config.selectedAddress !== selectedAddress) {\n this.configure({ selectedAddress });\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n\n onTokensStateChange(async ({ allTokens, allDetectedTokens }) => {\n const previousTokenAddresses = this.#getTokenAddresses(\n this.config.chainId,\n );\n this.configure({ allTokens, allDetectedTokens });\n const newTokenAddresses = this.#getTokenAddresses(this.config.chainId);\n if (\n !isEqual(previousTokenAddresses, newTokenAddresses) &&\n this.#pollState === PollState.Active\n ) {\n await this.updateExchangeRates();\n }\n });\n\n onNetworkStateChange(async ({ providerConfig }) => {\n const { chainId, ticker } = providerConfig;\n if (\n this.config.chainId !== chainId ||\n this.config.nativeCurrency !== ticker\n ) {\n this.update({ contractExchangeRates: {} });\n this.configure({ chainId, nativeCurrency: ticker });\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n });\n }\n\n /**\n * Get the user's tokens for the given chain.\n *\n * @param chainId - The chain ID.\n * @returns The list of tokens addresses for the current chain\n */\n #getTokenAddresses(chainId: Hex): Hex[] {\n const { allTokens, allDetectedTokens } = this.config;\n const tokens = allTokens[chainId]?.[this.config.selectedAddress] || [];\n const detectedTokens =\n allDetectedTokens[chainId]?.[this.config.selectedAddress] || [];\n\n return [\n ...new Set(\n [...tokens, ...detectedTokens].map((token) =>\n toHex(toChecksumHexAddress(token.address)),\n ),\n ),\n ].sort();\n }\n\n /**\n * Start (or restart) polling.\n */\n async start() {\n this.#stopPoll();\n this.#pollState = PollState.Active;\n await this.#poll();\n }\n\n /**\n * Stop polling.\n */\n stop() {\n this.#stopPoll();\n this.#pollState = PollState.Inactive;\n }\n\n /**\n * Clear the active polling timer, if present.\n */\n #stopPoll() {\n if (this.handle) {\n clearTimeout(this.handle);\n }\n }\n\n /**\n * Poll for exchange rate updates.\n */\n async #poll() {\n await safelyExecute(() => this.updateExchangeRates());\n\n // Poll using recursive `setTimeout` instead of `setInterval` so that\n // requests don't stack if they take longer than the polling interval\n this.handle = setTimeout(() => {\n this.#poll();\n }, this.config.interval);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n const { chainId, nativeCurrency } = this.config;\n await this.updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n });\n }\n\n /**\n * Updates exchange rates for all tokens.\n *\n * @param options - The options to fetch exchange rates.\n * @param options.chainId - The chain ID.\n * @param options.nativeCurrency - The ticker for the chain.\n */\n async updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n }: {\n chainId: Hex;\n nativeCurrency: string;\n }) {\n if (this.disabled) {\n return;\n }\n\n const tokenAddresses = this.#getTokenAddresses(chainId);\n if (tokenAddresses.length === 0) {\n return;\n }\n\n const updateKey: `${Hex}:${string}` = `${chainId}:${nativeCurrency}`;\n if (updateKey in this.#inProcessExchangeRateUpdates) {\n // This prevents redundant updates\n // This promise is resolved after the in-progress update has finished,\n // and state has been updated.\n await this.#inProcessExchangeRateUpdates[updateKey];\n return;\n }\n\n const {\n promise: inProgressUpdate,\n resolve: updateSucceeded,\n reject: updateFailed,\n } = createDeferredPromise({ suppressUnhandledRejection: true });\n this.#inProcessExchangeRateUpdates[updateKey] = inProgressUpdate;\n\n try {\n const newContractExchangeRates = await this.#fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n\n const existingContractExchangeRates = this.state.contractExchangeRates;\n const updatedContractExchangeRates =\n chainId === this.config.chainId &&\n nativeCurrency === this.config.nativeCurrency\n ? newContractExchangeRates\n : existingContractExchangeRates;\n\n const existingContractExchangeRatesForChainId =\n this.state.contractExchangeRatesByChainId[chainId] ?? {};\n const updatedContractExchangeRatesForChainId = {\n ...this.state.contractExchangeRatesByChainId,\n [chainId]: {\n ...existingContractExchangeRatesForChainId,\n [nativeCurrency]: {\n ...existingContractExchangeRatesForChainId[nativeCurrency],\n ...newContractExchangeRates,\n },\n },\n };\n\n this.update({\n contractExchangeRates: updatedContractExchangeRates,\n contractExchangeRatesByChainId: updatedContractExchangeRatesForChainId,\n });\n updateSucceeded();\n } catch (error: unknown) {\n updateFailed(error);\n throw error;\n } finally {\n delete this.#inProcessExchangeRateUpdates[updateKey];\n }\n }\n\n /**\n * Uses the token prices service to retrieve exchange rates for tokens in a\n * particular currency.\n *\n * If the price API does not support the given chain ID, returns an empty\n * object.\n *\n * If the price API does not support the given currency, retrieves exchange\n * rates in a known currency instead, then converts those rates using the\n * exchange rate between the known currency and desired currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * exchange rates.\n * @returns A map from token address to its exchange rate in the native\n * currency, or an empty map if no exchange rates can be obtained for the\n * chain ID.\n */\n async #fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n if (!this.#tokenPricesService.validateChainIdSupported(chainId)) {\n return tokenAddresses.reduce((obj, tokenAddress) => {\n return {\n ...obj,\n [tokenAddress]: undefined,\n };\n }, {});\n }\n\n if (this.#tokenPricesService.validateCurrencySupported(nativeCurrency)) {\n return await this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n }\n\n return await this.#fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenAddresses,\n nativeCurrency,\n });\n }\n\n /**\n * Updates token rates for the given networkClientId\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.getNetworkClientById(networkClientId);\n await this.updateExchangeRatesByChainId({\n chainId: networkClient.configuration.chainId,\n nativeCurrency: networkClient.configuration.ticker,\n });\n }\n\n /**\n * Retrieves prices in the given currency for the given tokens on the given\n * chain. Ensures that token addresses are checksum addresses.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const tokenPricesByTokenAddress = await reduceInBatchesSerially<\n Hex,\n Awaited<ReturnType<AbstractTokenPricesService['fetchTokenPrices']>>\n >({\n values: tokenAddresses,\n batchSize: TOKEN_PRICES_BATCH_SIZE,\n eachBatch: async (allTokenPricesByTokenAddress, batch) => {\n const tokenPricesByTokenAddressForBatch =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenAddresses: batch,\n chainId,\n currency: nativeCurrency,\n });\n\n return {\n ...allTokenPricesByTokenAddress,\n ...tokenPricesByTokenAddressForBatch,\n };\n },\n initialResult: {},\n });\n\n return Object.entries(tokenPricesByTokenAddress).reduce(\n (obj, [tokenAddress, tokenPrice]) => {\n return {\n ...obj,\n [tokenAddress]: tokenPrice?.value,\n };\n },\n {},\n );\n }\n\n /**\n * If the price API does not support a given native currency, then we need to\n * convert it to a fallback currency and feed that currency into the price\n * API, then convert the prices to our desired native currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n tokenAddresses,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n nativeCurrency: string;\n }): Promise<ContractExchangeRates> {\n const [\n contractExchangeRates,\n fallbackCurrencyToNativeCurrencyConversionRate,\n ] = await Promise.all([\n this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId: this.config.chainId,\n nativeCurrency: FALL_BACK_VS_CURRENCY,\n }),\n getCurrencyConversionRate({\n from: FALL_BACK_VS_CURRENCY,\n to: nativeCurrency,\n }),\n ]);\n\n if (fallbackCurrencyToNativeCurrencyConversionRate === null) {\n return {};\n }\n\n return Object.entries(contractExchangeRates).reduce(\n (obj, [tokenAddress, tokenValue]) => {\n return {\n ...obj,\n [tokenAddress]: tokenValue\n ? tokenValue * fallbackCurrencyToNativeCurrencyConversionRate\n : undefined,\n };\n },\n {},\n );\n }\n}\n\n/**\n * A deferred Promise.\n *\n * A deferred Promise is one that can be resolved or rejected independently of\n * the Promise construction.\n */\ntype DeferredPromise = {\n /**\n * The Promise that has been deferred.\n */\n promise: Promise<void>;\n /**\n * A function that resolves the Promise.\n */\n resolve: () => void;\n /**\n * A function that rejects the Promise.\n */\n reject: (error: unknown) => void;\n};\n\n/**\n * Create a defered Promise.\n *\n * TODO: Migrate this to utils\n *\n * @param args - The arguments.\n * @param args.suppressUnhandledRejection - This option adds an empty error handler\n * to the Promise to suppress the UnhandledPromiseRejection error. This can be\n * useful if the deferred Promise is sometimes intentionally not used.\n * @returns A deferred Promise.\n */\nfunction createDeferredPromise({\n suppressUnhandledRejection = false,\n}: {\n suppressUnhandledRejection: boolean;\n}): DeferredPromise {\n let resolve: DeferredPromise['resolve'];\n let reject: DeferredPromise['reject'];\n const promise = new Promise<void>(\n (innerResolve: () => void, innerReject: () => void) => {\n resolve = innerResolve;\n reject = innerReject;\n },\n );\n\n if (suppressUnhandledRejection) {\n promise.catch((_error) => {\n // This handler is used to suppress the UnhandledPromiseRejection error\n });\n }\n\n // @ts-expect-error We know that these are assigned, but TypeScript doesn't\n return { promise, resolve, reject };\n}\n\nexport default TokenRatesController;\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Contract } from '@ethersproject/contracts';
|
|
3
|
+
import { Web3Provider } from '@ethersproject/providers';
|
|
3
4
|
import type { AddApprovalRequest } from '@metamask/approval-controller';
|
|
4
5
|
import type { BaseConfig, BaseState, RestrictedControllerMessenger } from '@metamask/base-controller';
|
|
5
6
|
import { BaseControllerV1 } from '@metamask/base-controller';
|
|
@@ -7,7 +8,6 @@ import type { NetworkClientId, NetworkController, NetworkState } from '@metamask
|
|
|
7
8
|
import type { PreferencesState } from '@metamask/preferences-controller';
|
|
8
9
|
import type { Hex } from '@metamask/utils';
|
|
9
10
|
import { EventEmitter } from 'events';
|
|
10
|
-
import type { AssetsContractController } from './AssetsContractController';
|
|
11
11
|
import type { TokenListState } from './TokenListController';
|
|
12
12
|
import type { Token } from './TokenRatesController';
|
|
13
13
|
/**
|
|
@@ -81,6 +81,7 @@ declare type AllowedActions = AddApprovalRequest;
|
|
|
81
81
|
* The messenger of the {@link TokensController}.
|
|
82
82
|
*/
|
|
83
83
|
export declare type TokensControllerMessenger = RestrictedControllerMessenger<typeof controllerName, AllowedActions, never, AllowedActions['type'], never>;
|
|
84
|
+
export declare const getDefaultTokensState: () => TokensState;
|
|
84
85
|
/**
|
|
85
86
|
* Controller that stores assets and exposes convenience methods
|
|
86
87
|
*/
|
|
@@ -103,7 +104,6 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
103
104
|
* Name of this controller used during composition
|
|
104
105
|
*/
|
|
105
106
|
name: string;
|
|
106
|
-
private readonly getERC20TokenName;
|
|
107
107
|
private readonly getNetworkClientById;
|
|
108
108
|
/**
|
|
109
109
|
* Creates a TokensController instance.
|
|
@@ -113,18 +113,16 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
113
113
|
* @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.
|
|
114
114
|
* @param options.onNetworkDidChange - Allows subscribing to network controller networkDidChange events.
|
|
115
115
|
* @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.
|
|
116
|
-
* @param options.getERC20TokenName - Gets the ERC-20 token name.
|
|
117
116
|
* @param options.getNetworkClientById - Gets the network client with the given id from the NetworkController.
|
|
118
117
|
* @param options.config - Initial options used to configure this controller.
|
|
119
118
|
* @param options.state - Initial state to set on this controller.
|
|
120
119
|
* @param options.messenger - The controller messenger.
|
|
121
120
|
*/
|
|
122
|
-
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkDidChange, onTokenListStateChange,
|
|
121
|
+
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkDidChange, onTokenListStateChange, getNetworkClientById, config, state, messenger, }: {
|
|
123
122
|
chainId: Hex;
|
|
124
123
|
onPreferencesStateChange: (listener: (preferencesState: PreferencesState) => void) => void;
|
|
125
124
|
onNetworkDidChange: (listener: (networkState: NetworkState) => void) => void;
|
|
126
125
|
onTokenListStateChange: (listener: (tokenListState: TokenListState) => void) => void;
|
|
127
|
-
getERC20TokenName: AssetsContractController['getERC20TokenName'];
|
|
128
126
|
getNetworkClientById: NetworkController['getNetworkClientById'];
|
|
129
127
|
config?: Partial<TokensConfig>;
|
|
130
128
|
state?: Partial<TokensState>;
|
|
@@ -201,6 +199,7 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
201
199
|
* interface.
|
|
202
200
|
*/
|
|
203
201
|
_detectIsERC721(tokenAddress: string, networkClientId?: NetworkClientId): Promise<any>;
|
|
202
|
+
_getProvider(networkClientId?: NetworkClientId): Web3Provider;
|
|
204
203
|
_createEthersContract(tokenAddress: string, abi: string, networkClientId?: NetworkClientId): Contract;
|
|
205
204
|
_generateRandomId(): string;
|
|
206
205
|
/**
|
|
@@ -212,7 +211,7 @@ export declare class TokensController extends BaseControllerV1<TokensConfig, Tok
|
|
|
212
211
|
* @param options.type - The asset type.
|
|
213
212
|
* @param options.interactingAddress - The address of the account that is requesting to watch the asset.
|
|
214
213
|
* @param options.networkClientId - Network Client ID.
|
|
215
|
-
* @returns
|
|
214
|
+
* @returns A promise that resolves if the asset was watched successfully, and rejects otherwise.
|
|
216
215
|
*/
|
|
217
216
|
watchAsset({ asset, type, interactingAddress, networkClientId, }: {
|
|
218
217
|
asset: Token;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"TokensController.d.ts","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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"}
|