@metamask-previews/assets-controllers 11.0.1-preview.3dbf14f
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 +235 -0
- package/LICENSE +20 -0
- package/README.md +30 -0
- package/dist/AccountTrackerController.d.ts +106 -0
- package/dist/AccountTrackerController.d.ts.map +1 -0
- package/dist/AccountTrackerController.js +163 -0
- package/dist/AccountTrackerController.js.map +1 -0
- package/dist/AssetsContractController.d.ts +188 -0
- package/dist/AssetsContractController.d.ts.map +1 -0
- package/dist/AssetsContractController.js +330 -0
- package/dist/AssetsContractController.js.map +1 -0
- package/dist/CurrencyRateController.d.ts +101 -0
- package/dist/CurrencyRateController.d.ts.map +1 -0
- package/dist/CurrencyRateController.js +219 -0
- package/dist/CurrencyRateController.js.map +1 -0
- package/dist/NftController.d.ts +466 -0
- package/dist/NftController.d.ts.map +1 -0
- package/dist/NftController.js +943 -0
- package/dist/NftController.js.map +1 -0
- package/dist/NftDetectionController.d.ts +182 -0
- package/dist/NftDetectionController.d.ts.map +1 -0
- package/dist/NftDetectionController.js +188 -0
- package/dist/NftDetectionController.js.map +1 -0
- package/dist/Standards/ERC20Standard.d.ts +50 -0
- package/dist/Standards/ERC20Standard.d.ts.map +1 -0
- package/dist/Standards/ERC20Standard.js +144 -0
- package/dist/Standards/ERC20Standard.js.map +1 -0
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts +79 -0
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.d.ts.map +1 -0
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js +148 -0
- package/dist/Standards/NftStandards/ERC1155/ERC1155Standard.js.map +1 -0
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.d.ts +89 -0
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.d.ts.map +1 -0
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.js +182 -0
- package/dist/Standards/NftStandards/ERC721/ERC721Standard.js.map +1 -0
- package/dist/Standards/standards-types.d.ts +15 -0
- package/dist/Standards/standards-types.d.ts.map +1 -0
- package/dist/Standards/standards-types.js +3 -0
- package/dist/Standards/standards-types.js.map +1 -0
- package/dist/TokenBalancesController.d.ts +71 -0
- package/dist/TokenBalancesController.d.ts.map +1 -0
- package/dist/TokenBalancesController.js +94 -0
- package/dist/TokenBalancesController.js.map +1 -0
- package/dist/TokenDetectionController.d.ts +87 -0
- package/dist/TokenDetectionController.d.ts.map +1 -0
- package/dist/TokenDetectionController.js +189 -0
- package/dist/TokenDetectionController.js.map +1 -0
- package/dist/TokenListController.d.ts +117 -0
- package/dist/TokenListController.d.ts.map +1 -0
- package/dist/TokenListController.js +248 -0
- package/dist/TokenListController.js.map +1 -0
- package/dist/TokenRatesController.d.ts +172 -0
- package/dist/TokenRatesController.d.ts.map +1 -0
- package/dist/TokenRatesController.js +327 -0
- package/dist/TokenRatesController.js.map +1 -0
- package/dist/TokensController.d.ts +250 -0
- package/dist/TokensController.d.ts.map +1 -0
- package/dist/TokensController.js +550 -0
- package/dist/TokensController.js.map +1 -0
- package/dist/assetsUtil.d.ts +109 -0
- package/dist/assetsUtil.d.ts.map +1 -0
- package/dist/assetsUtil.js +227 -0
- package/dist/assetsUtil.js.map +1 -0
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -0
- package/dist/crypto-compare.d.ts +13 -0
- package/dist/crypto-compare.d.ts.map +1 -0
- package/dist/crypto-compare.js +67 -0
- package/dist/crypto-compare.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/token-service.d.ts +31 -0
- package/dist/token-service.d.ts.map +1 -0
- package/dist/token-service.js +134 -0
- package/dist/token-service.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { BaseConfig, BaseState } from '@metamask/base-controller';
|
|
2
|
+
import { BaseController } from '@metamask/base-controller';
|
|
3
|
+
import type { NetworkState } from '@metamask/network-controller';
|
|
4
|
+
import type { PreferencesState } from '@metamask/preferences-controller';
|
|
5
|
+
import type { Hex } from '@metamask/utils';
|
|
6
|
+
import type { TokensState } from './TokensController';
|
|
7
|
+
/**
|
|
8
|
+
* @type CoinGeckoResponse
|
|
9
|
+
*
|
|
10
|
+
* CoinGecko API response representation
|
|
11
|
+
*/
|
|
12
|
+
export interface CoinGeckoResponse {
|
|
13
|
+
[address: string]: {
|
|
14
|
+
[currency: string]: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @type CoinGeckoPlatform
|
|
19
|
+
*
|
|
20
|
+
* CoinGecko supported platform API representation
|
|
21
|
+
*/
|
|
22
|
+
export interface CoinGeckoPlatform {
|
|
23
|
+
id: string;
|
|
24
|
+
chain_identifier: null | number;
|
|
25
|
+
name: string;
|
|
26
|
+
shortname: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @type Token
|
|
30
|
+
*
|
|
31
|
+
* Token representation
|
|
32
|
+
* @property address - Hex address of the token contract
|
|
33
|
+
* @property decimals - Number of decimals the token uses
|
|
34
|
+
* @property symbol - Symbol of the token
|
|
35
|
+
* @property image - Image of the token, url or bit32 image
|
|
36
|
+
*/
|
|
37
|
+
export interface Token {
|
|
38
|
+
address: string;
|
|
39
|
+
decimals: number;
|
|
40
|
+
symbol: string;
|
|
41
|
+
aggregators?: string[];
|
|
42
|
+
image?: string;
|
|
43
|
+
balanceError?: unknown;
|
|
44
|
+
isERC721?: boolean;
|
|
45
|
+
name?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @type TokenRatesConfig
|
|
49
|
+
*
|
|
50
|
+
* Token rates controller configuration
|
|
51
|
+
* @property interval - Polling interval used to fetch new token rates
|
|
52
|
+
* @property nativeCurrency - Current native currency selected to use base of rates
|
|
53
|
+
* @property chainId - Current network chainId
|
|
54
|
+
* @property tokens - List of tokens to track exchange rates for
|
|
55
|
+
* @property threshold - Threshold to invalidate the supportedChains
|
|
56
|
+
*/
|
|
57
|
+
export interface TokenRatesConfig extends BaseConfig {
|
|
58
|
+
interval: number;
|
|
59
|
+
nativeCurrency: string;
|
|
60
|
+
chainId: Hex;
|
|
61
|
+
selectedAddress: string;
|
|
62
|
+
allTokens: {
|
|
63
|
+
[chainId: Hex]: {
|
|
64
|
+
[key: string]: Token[];
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
allDetectedTokens: {
|
|
68
|
+
[chainId: Hex]: {
|
|
69
|
+
[key: string]: Token[];
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
threshold: number;
|
|
73
|
+
}
|
|
74
|
+
interface ContractExchangeRates {
|
|
75
|
+
[address: string]: number | undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* @type TokenRatesState
|
|
79
|
+
*
|
|
80
|
+
* Token rates controller state
|
|
81
|
+
* @property contractExchangeRates - Hash of token contract addresses to exchange rates
|
|
82
|
+
* @property supportedChains - Cached chain data
|
|
83
|
+
*/
|
|
84
|
+
export interface TokenRatesState extends BaseState {
|
|
85
|
+
contractExchangeRates: ContractExchangeRates;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Controller that passively polls on a set interval for token-to-fiat exchange rates
|
|
89
|
+
* for tokens stored in the TokensController
|
|
90
|
+
*/
|
|
91
|
+
export declare class TokenRatesController extends BaseController<TokenRatesConfig, TokenRatesState> {
|
|
92
|
+
#private;
|
|
93
|
+
private handle?;
|
|
94
|
+
private tokenList;
|
|
95
|
+
private supportedChains;
|
|
96
|
+
private supportedVsCurrencies;
|
|
97
|
+
/**
|
|
98
|
+
* Name of this controller used during composition
|
|
99
|
+
*/
|
|
100
|
+
name: string;
|
|
101
|
+
/**
|
|
102
|
+
* Creates a TokenRatesController instance.
|
|
103
|
+
*
|
|
104
|
+
* @param options - The controller options.
|
|
105
|
+
* @param options.chainId - The chain ID of the current network.
|
|
106
|
+
* @param options.ticker - The ticker for the current network.
|
|
107
|
+
* @param options.selectedAddress - The current selected address.
|
|
108
|
+
* @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.
|
|
109
|
+
* @param options.onTokensStateChange - Allows subscribing to token controller state changes.
|
|
110
|
+
* @param options.onNetworkStateChange - Allows subscribing to network state changes.
|
|
111
|
+
* @param config - Initial options used to configure this controller.
|
|
112
|
+
* @param state - Initial state to set on this controller.
|
|
113
|
+
*/
|
|
114
|
+
constructor({ chainId: initialChainId, ticker: initialTicker, selectedAddress: initialSelectedAddress, onPreferencesStateChange, onTokensStateChange, onNetworkStateChange, }: {
|
|
115
|
+
chainId: Hex;
|
|
116
|
+
ticker: string;
|
|
117
|
+
selectedAddress: string;
|
|
118
|
+
onPreferencesStateChange: (listener: (preferencesState: PreferencesState) => void) => void;
|
|
119
|
+
onTokensStateChange: (listener: (tokensState: TokensState) => void) => void;
|
|
120
|
+
onNetworkStateChange: (listener: (networkState: NetworkState) => void) => void;
|
|
121
|
+
}, config?: Partial<TokenRatesConfig>, state?: Partial<TokenRatesState>);
|
|
122
|
+
/**
|
|
123
|
+
* Start (or restart) polling.
|
|
124
|
+
*/
|
|
125
|
+
start(): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Stop polling.
|
|
128
|
+
*/
|
|
129
|
+
stop(): void;
|
|
130
|
+
/**
|
|
131
|
+
* Fetches a pairs of token address and native currency.
|
|
132
|
+
*
|
|
133
|
+
* @param chainSlug - Chain string identifier.
|
|
134
|
+
* @param vsCurrency - Query according to tokens in tokenList and native currency.
|
|
135
|
+
* @returns The exchange rates for the given pairs.
|
|
136
|
+
*/
|
|
137
|
+
fetchExchangeRate(chainSlug: string, vsCurrency: string): Promise<CoinGeckoResponse>;
|
|
138
|
+
/**
|
|
139
|
+
* Checks if the current native currency is a supported vs currency to use
|
|
140
|
+
* to query for token exchange rates.
|
|
141
|
+
*
|
|
142
|
+
* @param nativeCurrency - The native currency of the currently active network.
|
|
143
|
+
* @returns A boolean indicating whether it's a supported vsCurrency.
|
|
144
|
+
*/
|
|
145
|
+
private checkIsSupportedVsCurrency;
|
|
146
|
+
/**
|
|
147
|
+
* Gets current chain ID slug from cached supported platforms CoinGecko API response.
|
|
148
|
+
* If cached supported platforms response is stale, fetches and updates it.
|
|
149
|
+
*
|
|
150
|
+
* @returns The CoinGecko slug for the current chain ID.
|
|
151
|
+
*/
|
|
152
|
+
getChainSlug(): Promise<string | null>;
|
|
153
|
+
/**
|
|
154
|
+
* Updates exchange rates for all tokens.
|
|
155
|
+
*/
|
|
156
|
+
updateExchangeRates(): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Checks if the active network's native currency is supported by the coingecko API.
|
|
159
|
+
* If supported, it fetches and maps contractExchange rates to a format to be consumed by the UI.
|
|
160
|
+
* If not supported, it fetches contractExchange rates and maps them from token/fallback-currency
|
|
161
|
+
* to token/nativeCurrency.
|
|
162
|
+
*
|
|
163
|
+
* @param nativeCurrency - The native currency of the currently active network.
|
|
164
|
+
* @param slug - The unique slug used to id the chain by the coingecko api
|
|
165
|
+
* should be used to query token exchange rates.
|
|
166
|
+
* @returns An object with conversion rates for each token
|
|
167
|
+
* related to the network's native currency.
|
|
168
|
+
*/
|
|
169
|
+
fetchAndMapExchangeRates(nativeCurrency: string, slug: string): Promise<ContractExchangeRates>;
|
|
170
|
+
}
|
|
171
|
+
export default TokenRatesController;
|
|
172
|
+
//# sourceMappingURL=TokenRatesController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenRatesController.d.ts","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
12
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
13
|
+
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");
|
|
14
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
15
|
+
};
|
|
16
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
17
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
18
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
19
|
+
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");
|
|
20
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
21
|
+
};
|
|
22
|
+
var _TokenRatesController_instances, _TokenRatesController_pollState, _TokenRatesController_updateTokenList, _TokenRatesController_stopPoll, _TokenRatesController_poll;
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.TokenRatesController = void 0;
|
|
25
|
+
const base_controller_1 = require("@metamask/base-controller");
|
|
26
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
27
|
+
const crypto_compare_1 = require("./crypto-compare");
|
|
28
|
+
var PollState;
|
|
29
|
+
(function (PollState) {
|
|
30
|
+
PollState["Active"] = "Active";
|
|
31
|
+
PollState["Inactive"] = "Inactive";
|
|
32
|
+
})(PollState || (PollState = {}));
|
|
33
|
+
const CoinGeckoApi = {
|
|
34
|
+
BASE_URL: 'https://api.coingecko.com/api/v3',
|
|
35
|
+
getTokenPriceURL(chainSlug, query) {
|
|
36
|
+
return `${this.BASE_URL}/simple/token_price/${chainSlug}?${query}`;
|
|
37
|
+
},
|
|
38
|
+
getPlatformsURL() {
|
|
39
|
+
return `${this.BASE_URL}/asset_platforms`;
|
|
40
|
+
},
|
|
41
|
+
getSupportedVsCurrencies() {
|
|
42
|
+
return `${this.BASE_URL}/simple/supported_vs_currencies`;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Finds the chain slug in the data array given a chainId.
|
|
47
|
+
*
|
|
48
|
+
* @param chainId - The current chain ID.
|
|
49
|
+
* @param data - A list platforms supported by the CoinGecko API.
|
|
50
|
+
* @returns The CoinGecko slug for the given chain ID, or `null` if the slug was not found.
|
|
51
|
+
*/
|
|
52
|
+
function findChainSlug(chainId, data) {
|
|
53
|
+
var _a;
|
|
54
|
+
if (!data) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const chain = (_a = data.find(({ chain_identifier }) => chain_identifier !== null && (0, controller_utils_1.toHex)(chain_identifier) === chainId)) !== null && _a !== void 0 ? _a : null;
|
|
58
|
+
return (chain === null || chain === void 0 ? void 0 : chain.id) || null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Controller that passively polls on a set interval for token-to-fiat exchange rates
|
|
62
|
+
* for tokens stored in the TokensController
|
|
63
|
+
*/
|
|
64
|
+
class TokenRatesController extends base_controller_1.BaseController {
|
|
65
|
+
/**
|
|
66
|
+
* Creates a TokenRatesController instance.
|
|
67
|
+
*
|
|
68
|
+
* @param options - The controller options.
|
|
69
|
+
* @param options.chainId - The chain ID of the current network.
|
|
70
|
+
* @param options.ticker - The ticker for the current network.
|
|
71
|
+
* @param options.selectedAddress - The current selected address.
|
|
72
|
+
* @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.
|
|
73
|
+
* @param options.onTokensStateChange - Allows subscribing to token controller state changes.
|
|
74
|
+
* @param options.onNetworkStateChange - Allows subscribing to network state changes.
|
|
75
|
+
* @param config - Initial options used to configure this controller.
|
|
76
|
+
* @param state - Initial state to set on this controller.
|
|
77
|
+
*/
|
|
78
|
+
constructor({ chainId: initialChainId, ticker: initialTicker, selectedAddress: initialSelectedAddress, onPreferencesStateChange, onTokensStateChange, onNetworkStateChange, }, config, state) {
|
|
79
|
+
super(config, state);
|
|
80
|
+
_TokenRatesController_instances.add(this);
|
|
81
|
+
this.tokenList = [];
|
|
82
|
+
this.supportedChains = {
|
|
83
|
+
timestamp: 0,
|
|
84
|
+
data: null,
|
|
85
|
+
};
|
|
86
|
+
this.supportedVsCurrencies = {
|
|
87
|
+
timestamp: 0,
|
|
88
|
+
data: [],
|
|
89
|
+
};
|
|
90
|
+
_TokenRatesController_pollState.set(this, PollState.Inactive);
|
|
91
|
+
/**
|
|
92
|
+
* Name of this controller used during composition
|
|
93
|
+
*/
|
|
94
|
+
this.name = 'TokenRatesController';
|
|
95
|
+
this.defaultConfig = {
|
|
96
|
+
disabled: false,
|
|
97
|
+
interval: 3 * 60 * 1000,
|
|
98
|
+
nativeCurrency: initialTicker,
|
|
99
|
+
chainId: initialChainId,
|
|
100
|
+
selectedAddress: initialSelectedAddress,
|
|
101
|
+
allTokens: {},
|
|
102
|
+
allDetectedTokens: {},
|
|
103
|
+
threshold: 6 * 60 * 60 * 1000,
|
|
104
|
+
};
|
|
105
|
+
this.defaultState = {
|
|
106
|
+
contractExchangeRates: {},
|
|
107
|
+
};
|
|
108
|
+
this.initialize();
|
|
109
|
+
if (config === null || config === void 0 ? void 0 : config.disabled) {
|
|
110
|
+
this.configure({ disabled: true }, false, false);
|
|
111
|
+
}
|
|
112
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
|
|
113
|
+
onPreferencesStateChange(({ selectedAddress }) => __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
if (this.config.selectedAddress !== selectedAddress) {
|
|
115
|
+
this.configure({ selectedAddress });
|
|
116
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
|
|
117
|
+
if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
|
|
118
|
+
yield this.updateExchangeRates();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
onTokensStateChange(({ allTokens, allDetectedTokens }) => __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
// These two state properties are assumed to be immutable
|
|
124
|
+
if (this.config.allTokens !== allTokens ||
|
|
125
|
+
this.config.allDetectedTokens !== allDetectedTokens) {
|
|
126
|
+
this.configure({ allTokens, allDetectedTokens });
|
|
127
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
|
|
128
|
+
if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
|
|
129
|
+
yield this.updateExchangeRates();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}));
|
|
133
|
+
onNetworkStateChange(({ providerConfig }) => __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
const { chainId, ticker } = providerConfig;
|
|
135
|
+
if (this.config.chainId !== chainId ||
|
|
136
|
+
this.config.nativeCurrency !== ticker) {
|
|
137
|
+
this.update({ contractExchangeRates: {} });
|
|
138
|
+
this.configure({ chainId, nativeCurrency: ticker });
|
|
139
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_updateTokenList).call(this);
|
|
140
|
+
if (__classPrivateFieldGet(this, _TokenRatesController_pollState, "f") === PollState.Active) {
|
|
141
|
+
yield this.updateExchangeRates();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Start (or restart) polling.
|
|
148
|
+
*/
|
|
149
|
+
start() {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_stopPoll).call(this);
|
|
152
|
+
__classPrivateFieldSet(this, _TokenRatesController_pollState, PollState.Active, "f");
|
|
153
|
+
yield __classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_poll).call(this);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Stop polling.
|
|
158
|
+
*/
|
|
159
|
+
stop() {
|
|
160
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_stopPoll).call(this);
|
|
161
|
+
__classPrivateFieldSet(this, _TokenRatesController_pollState, PollState.Inactive, "f");
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Fetches a pairs of token address and native currency.
|
|
165
|
+
*
|
|
166
|
+
* @param chainSlug - Chain string identifier.
|
|
167
|
+
* @param vsCurrency - Query according to tokens in tokenList and native currency.
|
|
168
|
+
* @returns The exchange rates for the given pairs.
|
|
169
|
+
*/
|
|
170
|
+
fetchExchangeRate(chainSlug, vsCurrency) {
|
|
171
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
172
|
+
const tokenPairs = this.tokenList.map((token) => token.address).join(',');
|
|
173
|
+
const query = `contract_addresses=${tokenPairs}&vs_currencies=${vsCurrency.toLowerCase()}`;
|
|
174
|
+
return (0, controller_utils_1.handleFetch)(CoinGeckoApi.getTokenPriceURL(chainSlug, query));
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Checks if the current native currency is a supported vs currency to use
|
|
179
|
+
* to query for token exchange rates.
|
|
180
|
+
*
|
|
181
|
+
* @param nativeCurrency - The native currency of the currently active network.
|
|
182
|
+
* @returns A boolean indicating whether it's a supported vsCurrency.
|
|
183
|
+
*/
|
|
184
|
+
checkIsSupportedVsCurrency(nativeCurrency) {
|
|
185
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
186
|
+
const { threshold } = this.config;
|
|
187
|
+
const { timestamp, data } = this.supportedVsCurrencies;
|
|
188
|
+
const now = Date.now();
|
|
189
|
+
if (now - timestamp > threshold) {
|
|
190
|
+
const currencies = yield (0, controller_utils_1.handleFetch)(CoinGeckoApi.getSupportedVsCurrencies());
|
|
191
|
+
this.supportedVsCurrencies = {
|
|
192
|
+
data: currencies,
|
|
193
|
+
timestamp: Date.now(),
|
|
194
|
+
};
|
|
195
|
+
return currencies.includes(nativeCurrency.toLowerCase());
|
|
196
|
+
}
|
|
197
|
+
return data.includes(nativeCurrency.toLowerCase());
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Gets current chain ID slug from cached supported platforms CoinGecko API response.
|
|
202
|
+
* If cached supported platforms response is stale, fetches and updates it.
|
|
203
|
+
*
|
|
204
|
+
* @returns The CoinGecko slug for the current chain ID.
|
|
205
|
+
*/
|
|
206
|
+
getChainSlug() {
|
|
207
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
208
|
+
const { threshold, chainId } = this.config;
|
|
209
|
+
const { data, timestamp } = this.supportedChains;
|
|
210
|
+
const now = Date.now();
|
|
211
|
+
if (now - timestamp > threshold) {
|
|
212
|
+
const platforms = yield (0, controller_utils_1.handleFetch)(CoinGeckoApi.getPlatformsURL());
|
|
213
|
+
this.supportedChains = {
|
|
214
|
+
data: platforms,
|
|
215
|
+
timestamp: Date.now(),
|
|
216
|
+
};
|
|
217
|
+
return findChainSlug(chainId, platforms);
|
|
218
|
+
}
|
|
219
|
+
return findChainSlug(chainId, data);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Updates exchange rates for all tokens.
|
|
224
|
+
*/
|
|
225
|
+
updateExchangeRates() {
|
|
226
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
227
|
+
if (this.tokenList.length === 0 || this.disabled) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const slug = yield this.getChainSlug();
|
|
231
|
+
let newContractExchangeRates = {};
|
|
232
|
+
if (!slug) {
|
|
233
|
+
this.tokenList.forEach((token) => {
|
|
234
|
+
const address = (0, controller_utils_1.toChecksumHexAddress)(token.address);
|
|
235
|
+
newContractExchangeRates[address] = undefined;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
const { nativeCurrency } = this.config;
|
|
240
|
+
newContractExchangeRates = yield this.fetchAndMapExchangeRates(nativeCurrency, slug);
|
|
241
|
+
}
|
|
242
|
+
this.update({ contractExchangeRates: newContractExchangeRates });
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Checks if the active network's native currency is supported by the coingecko API.
|
|
247
|
+
* If supported, it fetches and maps contractExchange rates to a format to be consumed by the UI.
|
|
248
|
+
* If not supported, it fetches contractExchange rates and maps them from token/fallback-currency
|
|
249
|
+
* to token/nativeCurrency.
|
|
250
|
+
*
|
|
251
|
+
* @param nativeCurrency - The native currency of the currently active network.
|
|
252
|
+
* @param slug - The unique slug used to id the chain by the coingecko api
|
|
253
|
+
* should be used to query token exchange rates.
|
|
254
|
+
* @returns An object with conversion rates for each token
|
|
255
|
+
* related to the network's native currency.
|
|
256
|
+
*/
|
|
257
|
+
fetchAndMapExchangeRates(nativeCurrency, slug) {
|
|
258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
259
|
+
const contractExchangeRates = {};
|
|
260
|
+
// check if native currency is supported as a vs_currency by the API
|
|
261
|
+
const nativeCurrencySupported = yield this.checkIsSupportedVsCurrency(nativeCurrency);
|
|
262
|
+
if (nativeCurrencySupported) {
|
|
263
|
+
// If it is we can do a simple fetch against the CoinGecko API
|
|
264
|
+
const prices = yield this.fetchExchangeRate(slug, nativeCurrency);
|
|
265
|
+
this.tokenList.forEach((token) => {
|
|
266
|
+
const price = prices[token.address.toLowerCase()];
|
|
267
|
+
contractExchangeRates[(0, controller_utils_1.toChecksumHexAddress)(token.address)] = price
|
|
268
|
+
? price[nativeCurrency.toLowerCase()]
|
|
269
|
+
: 0;
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
// if native currency is not supported we need to use a fallback vsCurrency, get the exchange rates
|
|
274
|
+
// in token/fallback-currency format and convert them to expected token/nativeCurrency format.
|
|
275
|
+
let tokenExchangeRates;
|
|
276
|
+
let vsCurrencyToNativeCurrencyConversionRate = 0;
|
|
277
|
+
try {
|
|
278
|
+
[
|
|
279
|
+
tokenExchangeRates,
|
|
280
|
+
{ conversionRate: vsCurrencyToNativeCurrencyConversionRate },
|
|
281
|
+
] = yield Promise.all([
|
|
282
|
+
this.fetchExchangeRate(slug, controller_utils_1.FALL_BACK_VS_CURRENCY),
|
|
283
|
+
(0, crypto_compare_1.fetchExchangeRate)(nativeCurrency, controller_utils_1.FALL_BACK_VS_CURRENCY, false),
|
|
284
|
+
]);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
if (error instanceof Error &&
|
|
288
|
+
error.message.includes('market does not exist for this coin pair')) {
|
|
289
|
+
return {};
|
|
290
|
+
}
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
for (const [tokenAddress, conversion] of Object.entries(tokenExchangeRates)) {
|
|
294
|
+
const tokenToVsCurrencyConversionRate = conversion[controller_utils_1.FALL_BACK_VS_CURRENCY.toLowerCase()];
|
|
295
|
+
contractExchangeRates[(0, controller_utils_1.toChecksumHexAddress)(tokenAddress)] =
|
|
296
|
+
tokenToVsCurrencyConversionRate *
|
|
297
|
+
vsCurrencyToNativeCurrencyConversionRate;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return contractExchangeRates;
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
exports.TokenRatesController = TokenRatesController;
|
|
305
|
+
_TokenRatesController_pollState = new WeakMap(), _TokenRatesController_instances = new WeakSet(), _TokenRatesController_updateTokenList = function _TokenRatesController_updateTokenList() {
|
|
306
|
+
var _a, _b;
|
|
307
|
+
const { allTokens, allDetectedTokens } = this.config;
|
|
308
|
+
const tokens = ((_a = allTokens[this.config.chainId]) === null || _a === void 0 ? void 0 : _a[this.config.selectedAddress]) || [];
|
|
309
|
+
const detectedTokens = ((_b = allDetectedTokens[this.config.chainId]) === null || _b === void 0 ? void 0 : _b[this.config.selectedAddress]) ||
|
|
310
|
+
[];
|
|
311
|
+
this.tokenList = [...tokens, ...detectedTokens];
|
|
312
|
+
}, _TokenRatesController_stopPoll = function _TokenRatesController_stopPoll() {
|
|
313
|
+
if (this.handle) {
|
|
314
|
+
clearTimeout(this.handle);
|
|
315
|
+
}
|
|
316
|
+
}, _TokenRatesController_poll = function _TokenRatesController_poll() {
|
|
317
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
318
|
+
yield (0, controller_utils_1.safelyExecute)(() => this.updateExchangeRates());
|
|
319
|
+
// Poll using recursive `setTimeout` instead of `setInterval` so that
|
|
320
|
+
// requests don't stack if they take longer than the polling interval
|
|
321
|
+
this.handle = setTimeout(() => {
|
|
322
|
+
__classPrivateFieldGet(this, _TokenRatesController_instances, "m", _TokenRatesController_poll).call(this);
|
|
323
|
+
}, this.config.interval);
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
exports.default = TokenRatesController;
|
|
327
|
+
//# sourceMappingURL=TokenRatesController.js.map
|
|
@@ -0,0 +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 { BaseController } from '@metamask/base-controller';\nimport {\n safelyExecute,\n handleFetch,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n toHex,\n} from '@metamask/controller-utils';\nimport type { NetworkState } from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport { fetchExchangeRate as fetchNativeExchangeRate } from './crypto-compare';\nimport type { TokensState } from './TokensController';\n\n/**\n * @type CoinGeckoResponse\n *\n * CoinGecko API response representation\n */\nexport interface CoinGeckoResponse {\n [address: string]: {\n [currency: string]: number;\n };\n}\n/**\n * @type CoinGeckoPlatform\n *\n * CoinGecko supported platform API representation\n */\nexport interface CoinGeckoPlatform {\n id: string;\n chain_identifier: null | number;\n name: string;\n shortname: string;\n}\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 */\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 */\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\ninterface ContractExchangeRates {\n [address: string]: number | undefined;\n}\n\ninterface SupportedChainsCache {\n timestamp: number;\n data: CoinGeckoPlatform[] | null;\n}\n\ninterface SupportedVsCurrenciesCache {\n timestamp: number;\n data: string[];\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\n * @property supportedChains - Cached chain data\n */\nexport interface TokenRatesState extends BaseState {\n contractExchangeRates: ContractExchangeRates;\n}\n\nconst CoinGeckoApi = {\n BASE_URL: 'https://api.coingecko.com/api/v3',\n getTokenPriceURL(chainSlug: string, query: string) {\n return `${this.BASE_URL}/simple/token_price/${chainSlug}?${query}`;\n },\n getPlatformsURL() {\n return `${this.BASE_URL}/asset_platforms`;\n },\n getSupportedVsCurrencies() {\n return `${this.BASE_URL}/simple/supported_vs_currencies`;\n },\n};\n\n/**\n * Finds the chain slug in the data array given a chainId.\n *\n * @param chainId - The current chain ID.\n * @param data - A list platforms supported by the CoinGecko API.\n * @returns The CoinGecko slug for the given chain ID, or `null` if the slug was not found.\n */\nfunction findChainSlug(\n chainId: Hex,\n data: CoinGeckoPlatform[] | null,\n): string | null {\n if (!data) {\n return null;\n }\n const chain =\n data.find(\n ({ chain_identifier }) =>\n chain_identifier !== null && toHex(chain_identifier) === chainId,\n ) ?? null;\n return chain?.id || null;\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 BaseController<\n TokenRatesConfig,\n TokenRatesState\n> {\n private handle?: ReturnType<typeof setTimeout>;\n\n private tokenList: Token[] = [];\n\n private supportedChains: SupportedChainsCache = {\n timestamp: 0,\n data: null,\n };\n\n private supportedVsCurrencies: SupportedVsCurrenciesCache = {\n timestamp: 0,\n data: [],\n };\n\n #pollState = PollState.Inactive;\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenRatesController';\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\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 config - Initial options used to configure this controller.\n * @param state - Initial state to set on this controller.\n */\n constructor(\n {\n chainId: initialChainId,\n ticker: initialTicker,\n selectedAddress: initialSelectedAddress,\n onPreferencesStateChange,\n onTokensStateChange,\n onNetworkStateChange,\n }: {\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 },\n config?: Partial<TokenRatesConfig>,\n state?: Partial<TokenRatesState>,\n ) {\n super(config, state);\n this.defaultConfig = {\n disabled: false,\n interval: 3 * 60 * 1000,\n nativeCurrency: initialTicker,\n chainId: initialChainId,\n selectedAddress: initialSelectedAddress,\n allTokens: {}, // TODO: initialize these correctly, maybe as part of BaseControllerV2 migration\n allDetectedTokens: {},\n threshold: 6 * 60 * 60 * 1000,\n };\n\n this.defaultState = {\n contractExchangeRates: {},\n };\n this.initialize();\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 * Fetches a pairs of token address and native currency.\n *\n * @param chainSlug - Chain string identifier.\n * @param vsCurrency - Query according to tokens in tokenList and native currency.\n * @returns The exchange rates for the given pairs.\n */\n async fetchExchangeRate(\n chainSlug: string,\n vsCurrency: string,\n ): Promise<CoinGeckoResponse> {\n const tokenPairs = this.tokenList.map((token) => token.address).join(',');\n const query = `contract_addresses=${tokenPairs}&vs_currencies=${vsCurrency.toLowerCase()}`;\n return handleFetch(CoinGeckoApi.getTokenPriceURL(chainSlug, query));\n }\n\n /**\n * Checks if the current native currency is a supported vs currency to use\n * to query for token exchange rates.\n *\n * @param nativeCurrency - The native currency of the currently active network.\n * @returns A boolean indicating whether it's a supported vsCurrency.\n */\n private async checkIsSupportedVsCurrency(nativeCurrency: string) {\n const { threshold } = this.config;\n const { timestamp, data } = this.supportedVsCurrencies;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const currencies = await handleFetch(\n CoinGeckoApi.getSupportedVsCurrencies(),\n );\n this.supportedVsCurrencies = {\n data: currencies,\n timestamp: Date.now(),\n };\n return currencies.includes(nativeCurrency.toLowerCase());\n }\n\n return data.includes(nativeCurrency.toLowerCase());\n }\n\n /**\n * Gets current chain ID slug from cached supported platforms CoinGecko API response.\n * If cached supported platforms response is stale, fetches and updates it.\n *\n * @returns The CoinGecko slug for the current chain ID.\n */\n async getChainSlug(): Promise<string | null> {\n const { threshold, chainId } = this.config;\n const { data, timestamp } = this.supportedChains;\n\n const now = Date.now();\n\n if (now - timestamp > threshold) {\n const platforms = await handleFetch(CoinGeckoApi.getPlatformsURL());\n this.supportedChains = {\n data: platforms,\n timestamp: Date.now(),\n };\n return findChainSlug(chainId, platforms);\n }\n\n return findChainSlug(chainId, data);\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 const slug = await this.getChainSlug();\n\n let newContractExchangeRates: ContractExchangeRates = {};\n if (!slug) {\n this.tokenList.forEach((token) => {\n const address = toChecksumHexAddress(token.address);\n newContractExchangeRates[address] = undefined;\n });\n } else {\n const { nativeCurrency } = this.config;\n newContractExchangeRates = await this.fetchAndMapExchangeRates(\n nativeCurrency,\n slug,\n );\n }\n this.update({ contractExchangeRates: newContractExchangeRates });\n }\n\n /**\n * Checks if the active network's native currency is supported by the coingecko API.\n * If supported, it fetches and maps contractExchange rates to a format to be consumed by the UI.\n * If not supported, it fetches contractExchange rates and maps them from token/fallback-currency\n * to token/nativeCurrency.\n *\n * @param nativeCurrency - The native currency of the currently active network.\n * @param slug - The unique slug used to id the chain by the coingecko api\n * should be used to query token exchange rates.\n * @returns An object with conversion rates for each token\n * related to the network's native currency.\n */\n async fetchAndMapExchangeRates(\n nativeCurrency: string,\n slug: string,\n ): Promise<ContractExchangeRates> {\n const contractExchangeRates: ContractExchangeRates = {};\n\n // check if native currency is supported as a vs_currency by the API\n const nativeCurrencySupported = await this.checkIsSupportedVsCurrency(\n nativeCurrency,\n );\n\n if (nativeCurrencySupported) {\n // If it is we can do a simple fetch against the CoinGecko API\n const prices = await this.fetchExchangeRate(slug, nativeCurrency);\n this.tokenList.forEach((token) => {\n const price = prices[token.address.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(token.address)] = price\n ? price[nativeCurrency.toLowerCase()]\n : 0;\n });\n } else {\n // if native currency is not supported we need to use a fallback vsCurrency, get the exchange rates\n // in token/fallback-currency format and convert them to expected token/nativeCurrency format.\n let tokenExchangeRates;\n let vsCurrencyToNativeCurrencyConversionRate = 0;\n try {\n [\n tokenExchangeRates,\n { conversionRate: vsCurrencyToNativeCurrencyConversionRate },\n ] = await Promise.all([\n this.fetchExchangeRate(slug, FALL_BACK_VS_CURRENCY),\n fetchNativeExchangeRate(nativeCurrency, FALL_BACK_VS_CURRENCY, false),\n ]);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return {};\n }\n throw error;\n }\n\n for (const [tokenAddress, conversion] of Object.entries(\n tokenExchangeRates,\n )) {\n const tokenToVsCurrencyConversionRate =\n conversion[FALL_BACK_VS_CURRENCY.toLowerCase()];\n contractExchangeRates[toChecksumHexAddress(tokenAddress)] =\n tokenToVsCurrencyConversionRate *\n vsCurrencyToNativeCurrencyConversionRate;\n }\n }\n\n return contractExchangeRates;\n }\n}\n\nexport default TokenRatesController;\n"]}
|