@metamask/assets-controllers 52.0.0 → 53.1.0

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/dist/MultichainAssetsController/MultichainAssetsController.cjs +13 -1
  3. package/dist/MultichainAssetsController/MultichainAssetsController.cjs.map +1 -1
  4. package/dist/MultichainAssetsController/MultichainAssetsController.d.cts +12 -1
  5. package/dist/MultichainAssetsController/MultichainAssetsController.d.cts.map +1 -1
  6. package/dist/MultichainAssetsController/MultichainAssetsController.d.mts +12 -1
  7. package/dist/MultichainAssetsController/MultichainAssetsController.d.mts.map +1 -1
  8. package/dist/MultichainAssetsController/MultichainAssetsController.mjs +13 -1
  9. package/dist/MultichainAssetsController/MultichainAssetsController.mjs.map +1 -1
  10. package/dist/Standards/ERC20Standard.cjs +4 -1
  11. package/dist/Standards/ERC20Standard.cjs.map +1 -1
  12. package/dist/Standards/ERC20Standard.d.cts.map +1 -1
  13. package/dist/Standards/ERC20Standard.d.mts.map +1 -1
  14. package/dist/Standards/ERC20Standard.mjs +6 -3
  15. package/dist/Standards/ERC20Standard.mjs.map +1 -1
  16. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.cjs +170 -0
  17. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.cjs.map +1 -0
  18. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.d.cts +77 -0
  19. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.d.cts.map +1 -0
  20. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.d.mts +77 -0
  21. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.d.mts.map +1 -0
  22. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.mjs +165 -0
  23. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.mjs.map +1 -0
  24. package/dist/TokenSearchDiscoveryDataController/index.cjs +18 -0
  25. package/dist/TokenSearchDiscoveryDataController/index.cjs.map +1 -0
  26. package/dist/TokenSearchDiscoveryDataController/index.d.cts +3 -0
  27. package/dist/TokenSearchDiscoveryDataController/index.d.cts.map +1 -0
  28. package/dist/TokenSearchDiscoveryDataController/index.d.mts +3 -0
  29. package/dist/TokenSearchDiscoveryDataController/index.d.mts.map +1 -0
  30. package/dist/TokenSearchDiscoveryDataController/index.mjs +2 -0
  31. package/dist/TokenSearchDiscoveryDataController/index.mjs.map +1 -0
  32. package/dist/TokenSearchDiscoveryDataController/types.cjs +3 -0
  33. package/dist/TokenSearchDiscoveryDataController/types.cjs.map +1 -0
  34. package/dist/TokenSearchDiscoveryDataController/types.d.cts +19 -0
  35. package/dist/TokenSearchDiscoveryDataController/types.d.cts.map +1 -0
  36. package/dist/TokenSearchDiscoveryDataController/types.d.mts +19 -0
  37. package/dist/TokenSearchDiscoveryDataController/types.d.mts.map +1 -0
  38. package/dist/TokenSearchDiscoveryDataController/types.mjs +2 -0
  39. package/dist/TokenSearchDiscoveryDataController/types.mjs.map +1 -0
  40. package/dist/index.cjs +3 -1
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +2 -0
  43. package/dist/index.d.cts.map +1 -1
  44. package/dist/index.d.mts +2 -0
  45. package/dist/index.d.mts.map +1 -1
  46. package/dist/index.mjs +1 -0
  47. package/dist/index.mjs.map +1 -1
  48. package/package.json +10 -10
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ 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");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ 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");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _TokenSearchDiscoveryDataController_instances, _TokenSearchDiscoveryDataController_abortController, _TokenSearchDiscoveryDataController_tokenPricesService, _TokenSearchDiscoveryDataController_swapsSupportedChainIds, _TokenSearchDiscoveryDataController_fetchTokens, _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs, _TokenSearchDiscoveryDataController_fetchPriceData;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.TokenSearchDiscoveryDataController = exports.getDefaultTokenSearchDiscoveryDataControllerState = exports.MAX_TOKEN_DISPLAY_DATA_LENGTH = exports.controllerName = void 0;
16
+ const base_controller_1 = require("@metamask/base-controller");
17
+ const assetsUtil_1 = require("../assetsUtil.cjs");
18
+ const token_service_1 = require("../token-service.cjs");
19
+ // === GENERAL ===
20
+ exports.controllerName = 'TokenSearchDiscoveryDataController';
21
+ exports.MAX_TOKEN_DISPLAY_DATA_LENGTH = 10;
22
+ const tokenSearchDiscoveryDataControllerMetadata = {
23
+ tokenDisplayData: { persist: true, anonymous: false },
24
+ swapsTokenAddressesByChainId: { persist: true, anonymous: false },
25
+ };
26
+ /**
27
+ * Constructs the default {@link TokenSearchDiscoveryDataController} state. This allows
28
+ * consumers to provide a partial state object when initializing the controller
29
+ * and also helps in constructing complete state objects for this controller in
30
+ * tests.
31
+ *
32
+ * @returns The default {@link TokenSearchDiscoveryDataController} state.
33
+ */
34
+ function getDefaultTokenSearchDiscoveryDataControllerState() {
35
+ return {
36
+ tokenDisplayData: [],
37
+ swapsTokenAddressesByChainId: {},
38
+ };
39
+ }
40
+ exports.getDefaultTokenSearchDiscoveryDataControllerState = getDefaultTokenSearchDiscoveryDataControllerState;
41
+ /**
42
+ * The TokenSearchDiscoveryDataController manages the retrieval of token search results and token discovery.
43
+ * It fetches token search results and discovery data from the Portfolio API.
44
+ */
45
+ class TokenSearchDiscoveryDataController extends base_controller_1.BaseController {
46
+ constructor({ state = {}, messenger, tokenPricesService, swapsSupportedChainIds, fetchTokens, fetchSwapsTokensThresholdMs, }) {
47
+ super({
48
+ name: exports.controllerName,
49
+ metadata: tokenSearchDiscoveryDataControllerMetadata,
50
+ messenger,
51
+ state: {
52
+ ...getDefaultTokenSearchDiscoveryDataControllerState(),
53
+ ...state,
54
+ },
55
+ });
56
+ _TokenSearchDiscoveryDataController_instances.add(this);
57
+ _TokenSearchDiscoveryDataController_abortController.set(this, void 0);
58
+ _TokenSearchDiscoveryDataController_tokenPricesService.set(this, void 0);
59
+ _TokenSearchDiscoveryDataController_swapsSupportedChainIds.set(this, void 0);
60
+ _TokenSearchDiscoveryDataController_fetchTokens.set(this, void 0);
61
+ _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs.set(this, void 0);
62
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_abortController, new AbortController(), "f");
63
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_tokenPricesService, tokenPricesService, "f");
64
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_swapsSupportedChainIds, swapsSupportedChainIds, "f");
65
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_fetchTokens, fetchTokens, "f");
66
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs, fetchSwapsTokensThresholdMs, "f");
67
+ }
68
+ async fetchSwapsTokens(chainId) {
69
+ if (!__classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_swapsSupportedChainIds, "f").includes(chainId)) {
70
+ return;
71
+ }
72
+ const swapsTokens = this.state.swapsTokenAddressesByChainId[chainId];
73
+ if ((!swapsTokens ||
74
+ swapsTokens.lastFetched <
75
+ Date.now() - __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs, "f")) &&
76
+ !swapsTokens?.isFetching) {
77
+ try {
78
+ this.update((state) => {
79
+ if (!state.swapsTokenAddressesByChainId[chainId]) {
80
+ state.swapsTokenAddressesByChainId[chainId] = {
81
+ lastFetched: Date.now(),
82
+ addresses: [],
83
+ isFetching: true,
84
+ };
85
+ }
86
+ else {
87
+ state.swapsTokenAddressesByChainId[chainId].isFetching = true;
88
+ }
89
+ });
90
+ const tokens = await __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_fetchTokens, "f").call(this, chainId);
91
+ this.update((state) => {
92
+ state.swapsTokenAddressesByChainId[chainId] = {
93
+ lastFetched: Date.now(),
94
+ addresses: tokens.map((token) => token.address),
95
+ isFetching: false,
96
+ };
97
+ });
98
+ }
99
+ catch (error) {
100
+ console.error(error);
101
+ }
102
+ }
103
+ }
104
+ async fetchTokenDisplayData(chainId, address) {
105
+ await this.fetchSwapsTokens(chainId);
106
+ let tokenMetadata;
107
+ try {
108
+ tokenMetadata = await (0, token_service_1.fetchTokenMetadata)(chainId, address, __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_abortController, "f").signal);
109
+ }
110
+ catch (error) {
111
+ if (!(error instanceof Error) ||
112
+ !error.message.includes(token_service_1.TOKEN_METADATA_NO_SUPPORT_ERROR)) {
113
+ throw error;
114
+ }
115
+ }
116
+ const { currentCurrency } = this.messagingSystem.call('CurrencyRateController:getState');
117
+ let tokenDisplayData;
118
+ if (!tokenMetadata) {
119
+ tokenDisplayData = {
120
+ found: false,
121
+ address,
122
+ chainId,
123
+ currency: currentCurrency,
124
+ };
125
+ }
126
+ else {
127
+ const priceData = await __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_instances, "m", _TokenSearchDiscoveryDataController_fetchPriceData).call(this, chainId, address);
128
+ tokenDisplayData = {
129
+ found: true,
130
+ address,
131
+ chainId,
132
+ currency: currentCurrency,
133
+ token: {
134
+ ...tokenMetadata,
135
+ isERC721: false,
136
+ image: (0, assetsUtil_1.formatIconUrlWithProxy)({
137
+ chainId,
138
+ tokenAddress: address,
139
+ }),
140
+ },
141
+ price: priceData,
142
+ };
143
+ }
144
+ this.update((state) => {
145
+ state.tokenDisplayData = [
146
+ tokenDisplayData,
147
+ ...state.tokenDisplayData.filter((token) => token.address !== address ||
148
+ token.chainId !== chainId ||
149
+ token.currency !== currentCurrency),
150
+ ].slice(0, exports.MAX_TOKEN_DISPLAY_DATA_LENGTH);
151
+ });
152
+ }
153
+ }
154
+ exports.TokenSearchDiscoveryDataController = TokenSearchDiscoveryDataController;
155
+ _TokenSearchDiscoveryDataController_abortController = new WeakMap(), _TokenSearchDiscoveryDataController_tokenPricesService = new WeakMap(), _TokenSearchDiscoveryDataController_swapsSupportedChainIds = new WeakMap(), _TokenSearchDiscoveryDataController_fetchTokens = new WeakMap(), _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs = new WeakMap(), _TokenSearchDiscoveryDataController_instances = new WeakSet(), _TokenSearchDiscoveryDataController_fetchPriceData = async function _TokenSearchDiscoveryDataController_fetchPriceData(chainId, address) {
156
+ const { currentCurrency } = this.messagingSystem.call('CurrencyRateController:getState');
157
+ try {
158
+ const pricesData = await __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_tokenPricesService, "f").fetchTokenPrices({
159
+ chainId,
160
+ tokenAddresses: [address],
161
+ currency: currentCurrency,
162
+ });
163
+ return pricesData[address] ?? null;
164
+ }
165
+ catch (error) {
166
+ console.error(error);
167
+ return null;
168
+ }
169
+ };
170
+ //# sourceMappingURL=TokenSearchDiscoveryDataController.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenSearchDiscoveryDataController.cjs","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport type { TokenDisplayData } from './types';\nimport { formatIconUrlWithProxy } from '../assetsUtil';\nimport type { GetCurrencyRateState } from '../CurrencyRateController';\nimport type { AbstractTokenPricesService } from '../token-prices-service';\nimport type { TokenPrice } from '../token-prices-service/abstract-token-prices-service';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from '../token-service';\nimport type { TokenListToken } from '../TokenListController';\n\n// === GENERAL ===\n\nexport const controllerName = 'TokenSearchDiscoveryDataController';\n\nexport const MAX_TOKEN_DISPLAY_DATA_LENGTH = 10;\n\n// === STATE ===\n\nexport type TokenSearchDiscoveryDataControllerState = {\n tokenDisplayData: TokenDisplayData[];\n swapsTokenAddressesByChainId: Record<\n Hex,\n { lastFetched: number; addresses: string[]; isFetching: boolean }\n >;\n};\n\nconst tokenSearchDiscoveryDataControllerMetadata = {\n tokenDisplayData: { persist: true, anonymous: false },\n swapsTokenAddressesByChainId: { persist: true, anonymous: false },\n} as const;\n\n// === MESSENGER ===\n\n/**\n * The action which can be used to retrieve the state of the\n * {@link TokenSearchDiscoveryDataController}.\n */\nexport type TokenSearchDiscoveryDataControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerState\n >;\n\n/**\n * All actions that {@link TokenSearchDiscoveryDataController} registers, to be\n * called externally.\n */\nexport type TokenSearchDiscoveryDataControllerActions =\n TokenSearchDiscoveryDataControllerGetStateAction;\n\n/**\n * All actions that {@link TokenSearchDiscoveryDataController} calls internally.\n */\nexport type AllowedActions = GetCurrencyRateState;\n\n/**\n * The event that {@link TokenSearchDiscoveryDataController} publishes when updating\n * state.\n */\nexport type TokenSearchDiscoveryDataControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerState\n >;\n\n/**\n * All events that {@link TokenSearchDiscoveryDataController} publishes, to be\n * subscribed to externally.\n */\nexport type TokenSearchDiscoveryDataControllerEvents =\n TokenSearchDiscoveryDataControllerStateChangeEvent;\n\n/**\n * All events that {@link TokenSearchDiscoveryDataController} subscribes to internally.\n */\nexport type AllowedEvents = never;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * {@link TokenSearchDiscoveryDataController}.\n */\nexport type TokenSearchDiscoveryDataControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerActions | AllowedActions,\n TokenSearchDiscoveryDataControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Constructs the default {@link TokenSearchDiscoveryDataController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link TokenSearchDiscoveryDataController} state.\n */\nexport function getDefaultTokenSearchDiscoveryDataControllerState(): TokenSearchDiscoveryDataControllerState {\n return {\n tokenDisplayData: [],\n swapsTokenAddressesByChainId: {},\n };\n}\n\n/**\n * The TokenSearchDiscoveryDataController manages the retrieval of token search results and token discovery.\n * It fetches token search results and discovery data from the Portfolio API.\n */\nexport class TokenSearchDiscoveryDataController extends BaseController<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerState,\n TokenSearchDiscoveryDataControllerMessenger\n> {\n readonly #abortController: AbortController;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n readonly #swapsSupportedChainIds: Hex[];\n\n readonly #fetchTokens: (chainId: Hex) => Promise<{ address: string }[]>;\n\n readonly #fetchSwapsTokensThresholdMs: number;\n\n constructor({\n state = {},\n messenger,\n tokenPricesService,\n swapsSupportedChainIds,\n fetchTokens,\n fetchSwapsTokensThresholdMs,\n }: {\n state?: Partial<TokenSearchDiscoveryDataControllerState>;\n messenger: TokenSearchDiscoveryDataControllerMessenger;\n tokenPricesService: AbstractTokenPricesService;\n swapsSupportedChainIds: Hex[];\n fetchTokens: (chainId: Hex) => Promise<{ address: string }[]>;\n fetchSwapsTokensThresholdMs: number;\n }) {\n super({\n name: controllerName,\n metadata: tokenSearchDiscoveryDataControllerMetadata,\n messenger,\n state: {\n ...getDefaultTokenSearchDiscoveryDataControllerState(),\n ...state,\n },\n });\n\n this.#abortController = new AbortController();\n this.#tokenPricesService = tokenPricesService;\n this.#swapsSupportedChainIds = swapsSupportedChainIds;\n this.#fetchTokens = fetchTokens;\n this.#fetchSwapsTokensThresholdMs = fetchSwapsTokensThresholdMs;\n }\n\n async #fetchPriceData(\n chainId: Hex,\n address: string,\n ): Promise<TokenPrice<Hex, string> | null> {\n const { currentCurrency } = this.messagingSystem.call(\n 'CurrencyRateController:getState',\n );\n\n try {\n const pricesData = await this.#tokenPricesService.fetchTokenPrices({\n chainId,\n tokenAddresses: [address as Hex],\n currency: currentCurrency,\n });\n\n return pricesData[address as Hex] ?? null;\n } catch (error) {\n console.error(error);\n return null;\n }\n }\n\n async fetchSwapsTokens(chainId: Hex): Promise<void> {\n if (!this.#swapsSupportedChainIds.includes(chainId)) {\n return;\n }\n\n const swapsTokens = this.state.swapsTokenAddressesByChainId[chainId];\n if (\n (!swapsTokens ||\n swapsTokens.lastFetched <\n Date.now() - this.#fetchSwapsTokensThresholdMs) &&\n !swapsTokens?.isFetching\n ) {\n try {\n this.update((state) => {\n if (!state.swapsTokenAddressesByChainId[chainId]) {\n state.swapsTokenAddressesByChainId[chainId] = {\n lastFetched: Date.now(),\n addresses: [],\n isFetching: true,\n };\n } else {\n state.swapsTokenAddressesByChainId[chainId].isFetching = true;\n }\n });\n const tokens = await this.#fetchTokens(chainId);\n this.update((state) => {\n state.swapsTokenAddressesByChainId[chainId] = {\n lastFetched: Date.now(),\n addresses: tokens.map((token) => token.address),\n isFetching: false,\n };\n });\n } catch (error) {\n console.error(error);\n }\n }\n }\n\n async fetchTokenDisplayData(chainId: Hex, address: string): Promise<void> {\n await this.fetchSwapsTokens(chainId);\n\n let tokenMetadata: TokenListToken | undefined;\n try {\n tokenMetadata = await fetchTokenMetadata<TokenListToken>(\n chainId,\n address,\n this.#abortController.signal,\n );\n } catch (error) {\n if (\n !(error instanceof Error) ||\n !error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n throw error;\n }\n }\n\n const { currentCurrency } = this.messagingSystem.call(\n 'CurrencyRateController:getState',\n );\n\n let tokenDisplayData: TokenDisplayData;\n if (!tokenMetadata) {\n tokenDisplayData = {\n found: false,\n address,\n chainId,\n currency: currentCurrency,\n };\n } else {\n const priceData = await this.#fetchPriceData(chainId, address);\n tokenDisplayData = {\n found: true,\n address,\n chainId,\n currency: currentCurrency,\n token: {\n ...tokenMetadata,\n isERC721: false,\n image: formatIconUrlWithProxy({\n chainId,\n tokenAddress: address,\n }),\n },\n price: priceData,\n };\n }\n\n this.update((state) => {\n state.tokenDisplayData = [\n tokenDisplayData,\n ...state.tokenDisplayData.filter(\n (token) =>\n token.address !== address ||\n token.chainId !== chainId ||\n token.currency !== currentCurrency,\n ),\n ].slice(0, MAX_TOKEN_DISPLAY_DATA_LENGTH);\n });\n }\n}\n"]}
@@ -0,0 +1,77 @@
1
+ import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger } from "@metamask/base-controller";
2
+ import type { Hex } from "@metamask/utils";
3
+ import type { TokenDisplayData } from "./types.cjs";
4
+ import type { GetCurrencyRateState } from "../CurrencyRateController.cjs";
5
+ import type { AbstractTokenPricesService } from "../token-prices-service/index.cjs";
6
+ export declare const controllerName = "TokenSearchDiscoveryDataController";
7
+ export declare const MAX_TOKEN_DISPLAY_DATA_LENGTH = 10;
8
+ export type TokenSearchDiscoveryDataControllerState = {
9
+ tokenDisplayData: TokenDisplayData[];
10
+ swapsTokenAddressesByChainId: Record<Hex, {
11
+ lastFetched: number;
12
+ addresses: string[];
13
+ isFetching: boolean;
14
+ }>;
15
+ };
16
+ /**
17
+ * The action which can be used to retrieve the state of the
18
+ * {@link TokenSearchDiscoveryDataController}.
19
+ */
20
+ export type TokenSearchDiscoveryDataControllerGetStateAction = ControllerGetStateAction<typeof controllerName, TokenSearchDiscoveryDataControllerState>;
21
+ /**
22
+ * All actions that {@link TokenSearchDiscoveryDataController} registers, to be
23
+ * called externally.
24
+ */
25
+ export type TokenSearchDiscoveryDataControllerActions = TokenSearchDiscoveryDataControllerGetStateAction;
26
+ /**
27
+ * All actions that {@link TokenSearchDiscoveryDataController} calls internally.
28
+ */
29
+ export type AllowedActions = GetCurrencyRateState;
30
+ /**
31
+ * The event that {@link TokenSearchDiscoveryDataController} publishes when updating
32
+ * state.
33
+ */
34
+ export type TokenSearchDiscoveryDataControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, TokenSearchDiscoveryDataControllerState>;
35
+ /**
36
+ * All events that {@link TokenSearchDiscoveryDataController} publishes, to be
37
+ * subscribed to externally.
38
+ */
39
+ export type TokenSearchDiscoveryDataControllerEvents = TokenSearchDiscoveryDataControllerStateChangeEvent;
40
+ /**
41
+ * All events that {@link TokenSearchDiscoveryDataController} subscribes to internally.
42
+ */
43
+ export type AllowedEvents = never;
44
+ /**
45
+ * The messenger which is restricted to actions and events accessed by
46
+ * {@link TokenSearchDiscoveryDataController}.
47
+ */
48
+ export type TokenSearchDiscoveryDataControllerMessenger = RestrictedMessenger<typeof controllerName, TokenSearchDiscoveryDataControllerActions | AllowedActions, TokenSearchDiscoveryDataControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
49
+ /**
50
+ * Constructs the default {@link TokenSearchDiscoveryDataController} state. This allows
51
+ * consumers to provide a partial state object when initializing the controller
52
+ * and also helps in constructing complete state objects for this controller in
53
+ * tests.
54
+ *
55
+ * @returns The default {@link TokenSearchDiscoveryDataController} state.
56
+ */
57
+ export declare function getDefaultTokenSearchDiscoveryDataControllerState(): TokenSearchDiscoveryDataControllerState;
58
+ /**
59
+ * The TokenSearchDiscoveryDataController manages the retrieval of token search results and token discovery.
60
+ * It fetches token search results and discovery data from the Portfolio API.
61
+ */
62
+ export declare class TokenSearchDiscoveryDataController extends BaseController<typeof controllerName, TokenSearchDiscoveryDataControllerState, TokenSearchDiscoveryDataControllerMessenger> {
63
+ #private;
64
+ constructor({ state, messenger, tokenPricesService, swapsSupportedChainIds, fetchTokens, fetchSwapsTokensThresholdMs, }: {
65
+ state?: Partial<TokenSearchDiscoveryDataControllerState>;
66
+ messenger: TokenSearchDiscoveryDataControllerMessenger;
67
+ tokenPricesService: AbstractTokenPricesService;
68
+ swapsSupportedChainIds: Hex[];
69
+ fetchTokens: (chainId: Hex) => Promise<{
70
+ address: string;
71
+ }[]>;
72
+ fetchSwapsTokensThresholdMs: number;
73
+ });
74
+ fetchSwapsTokens(chainId: Hex): Promise<void>;
75
+ fetchTokenDisplayData(chainId: Hex, address: string): Promise<void>;
76
+ }
77
+ //# sourceMappingURL=TokenSearchDiscoveryDataController.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenSearchDiscoveryDataController.d.cts","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;AACnC,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAgB;AAEhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,sCAAkC;AACtE,OAAO,KAAK,EAAE,0BAA0B,EAAE,0CAAgC;AAU1E,eAAO,MAAM,cAAc,uCAAuC,CAAC;AAEnE,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAIhD,MAAM,MAAM,uCAAuC,GAAG;IACpD,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;IACrC,4BAA4B,EAAE,MAAM,CAClC,GAAG,EACH;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAClE,CAAC;CACH,CAAC;AASF;;;GAGG;AACH,MAAM,MAAM,gDAAgD,GAC1D,wBAAwB,CACtB,OAAO,cAAc,EACrB,uCAAuC,CACxC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,yCAAyC,GACnD,gDAAgD,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAElD;;;GAGG;AACH,MAAM,MAAM,kDAAkD,GAC5D,0BAA0B,CACxB,OAAO,cAAc,EACrB,uCAAuC,CACxC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,wCAAwC,GAClD,kDAAkD,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC;AAElC;;;GAGG;AACH,MAAM,MAAM,2CAA2C,GAAG,mBAAmB,CAC3E,OAAO,cAAc,EACrB,yCAAyC,GAAG,cAAc,EAC1D,wCAAwC,GAAG,aAAa,EACxD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,iDAAiD,IAAI,uCAAuC,CAK3G;AAED;;;GAGG;AACH,qBAAa,kCAAmC,SAAQ,cAAc,CACpE,OAAO,cAAc,EACrB,uCAAuC,EACvC,2CAA2C,CAC5C;;gBAWa,EACV,KAAU,EACV,SAAS,EACT,kBAAkB,EAClB,sBAAsB,EACtB,WAAW,EACX,2BAA2B,GAC5B,EAAE;QACD,KAAK,CAAC,EAAE,OAAO,CAAC,uCAAuC,CAAC,CAAC;QACzD,SAAS,EAAE,2CAA2C,CAAC;QACvD,kBAAkB,EAAE,0BAA0B,CAAC;QAC/C,sBAAsB,EAAE,GAAG,EAAE,CAAC;QAC9B,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC,CAAC;QAC9D,2BAA2B,EAAE,MAAM,CAAC;KACrC;IAwCK,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC7C,qBAAqB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA8D1E"}
@@ -0,0 +1,77 @@
1
+ import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger } from "@metamask/base-controller";
2
+ import type { Hex } from "@metamask/utils";
3
+ import type { TokenDisplayData } from "./types.mjs";
4
+ import type { GetCurrencyRateState } from "../CurrencyRateController.mjs";
5
+ import type { AbstractTokenPricesService } from "../token-prices-service/index.mjs";
6
+ export declare const controllerName = "TokenSearchDiscoveryDataController";
7
+ export declare const MAX_TOKEN_DISPLAY_DATA_LENGTH = 10;
8
+ export type TokenSearchDiscoveryDataControllerState = {
9
+ tokenDisplayData: TokenDisplayData[];
10
+ swapsTokenAddressesByChainId: Record<Hex, {
11
+ lastFetched: number;
12
+ addresses: string[];
13
+ isFetching: boolean;
14
+ }>;
15
+ };
16
+ /**
17
+ * The action which can be used to retrieve the state of the
18
+ * {@link TokenSearchDiscoveryDataController}.
19
+ */
20
+ export type TokenSearchDiscoveryDataControllerGetStateAction = ControllerGetStateAction<typeof controllerName, TokenSearchDiscoveryDataControllerState>;
21
+ /**
22
+ * All actions that {@link TokenSearchDiscoveryDataController} registers, to be
23
+ * called externally.
24
+ */
25
+ export type TokenSearchDiscoveryDataControllerActions = TokenSearchDiscoveryDataControllerGetStateAction;
26
+ /**
27
+ * All actions that {@link TokenSearchDiscoveryDataController} calls internally.
28
+ */
29
+ export type AllowedActions = GetCurrencyRateState;
30
+ /**
31
+ * The event that {@link TokenSearchDiscoveryDataController} publishes when updating
32
+ * state.
33
+ */
34
+ export type TokenSearchDiscoveryDataControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, TokenSearchDiscoveryDataControllerState>;
35
+ /**
36
+ * All events that {@link TokenSearchDiscoveryDataController} publishes, to be
37
+ * subscribed to externally.
38
+ */
39
+ export type TokenSearchDiscoveryDataControllerEvents = TokenSearchDiscoveryDataControllerStateChangeEvent;
40
+ /**
41
+ * All events that {@link TokenSearchDiscoveryDataController} subscribes to internally.
42
+ */
43
+ export type AllowedEvents = never;
44
+ /**
45
+ * The messenger which is restricted to actions and events accessed by
46
+ * {@link TokenSearchDiscoveryDataController}.
47
+ */
48
+ export type TokenSearchDiscoveryDataControllerMessenger = RestrictedMessenger<typeof controllerName, TokenSearchDiscoveryDataControllerActions | AllowedActions, TokenSearchDiscoveryDataControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
49
+ /**
50
+ * Constructs the default {@link TokenSearchDiscoveryDataController} state. This allows
51
+ * consumers to provide a partial state object when initializing the controller
52
+ * and also helps in constructing complete state objects for this controller in
53
+ * tests.
54
+ *
55
+ * @returns The default {@link TokenSearchDiscoveryDataController} state.
56
+ */
57
+ export declare function getDefaultTokenSearchDiscoveryDataControllerState(): TokenSearchDiscoveryDataControllerState;
58
+ /**
59
+ * The TokenSearchDiscoveryDataController manages the retrieval of token search results and token discovery.
60
+ * It fetches token search results and discovery data from the Portfolio API.
61
+ */
62
+ export declare class TokenSearchDiscoveryDataController extends BaseController<typeof controllerName, TokenSearchDiscoveryDataControllerState, TokenSearchDiscoveryDataControllerMessenger> {
63
+ #private;
64
+ constructor({ state, messenger, tokenPricesService, swapsSupportedChainIds, fetchTokens, fetchSwapsTokensThresholdMs, }: {
65
+ state?: Partial<TokenSearchDiscoveryDataControllerState>;
66
+ messenger: TokenSearchDiscoveryDataControllerMessenger;
67
+ tokenPricesService: AbstractTokenPricesService;
68
+ swapsSupportedChainIds: Hex[];
69
+ fetchTokens: (chainId: Hex) => Promise<{
70
+ address: string;
71
+ }[]>;
72
+ fetchSwapsTokensThresholdMs: number;
73
+ });
74
+ fetchSwapsTokens(chainId: Hex): Promise<void>;
75
+ fetchTokenDisplayData(chainId: Hex, address: string): Promise<void>;
76
+ }
77
+ //# sourceMappingURL=TokenSearchDiscoveryDataController.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenSearchDiscoveryDataController.d.mts","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;AACnC,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAgB;AAEhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,sCAAkC;AACtE,OAAO,KAAK,EAAE,0BAA0B,EAAE,0CAAgC;AAU1E,eAAO,MAAM,cAAc,uCAAuC,CAAC;AAEnE,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAIhD,MAAM,MAAM,uCAAuC,GAAG;IACpD,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;IACrC,4BAA4B,EAAE,MAAM,CAClC,GAAG,EACH;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAClE,CAAC;CACH,CAAC;AASF;;;GAGG;AACH,MAAM,MAAM,gDAAgD,GAC1D,wBAAwB,CACtB,OAAO,cAAc,EACrB,uCAAuC,CACxC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,yCAAyC,GACnD,gDAAgD,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAElD;;;GAGG;AACH,MAAM,MAAM,kDAAkD,GAC5D,0BAA0B,CACxB,OAAO,cAAc,EACrB,uCAAuC,CACxC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,wCAAwC,GAClD,kDAAkD,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC;AAElC;;;GAGG;AACH,MAAM,MAAM,2CAA2C,GAAG,mBAAmB,CAC3E,OAAO,cAAc,EACrB,yCAAyC,GAAG,cAAc,EAC1D,wCAAwC,GAAG,aAAa,EACxD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,iDAAiD,IAAI,uCAAuC,CAK3G;AAED;;;GAGG;AACH,qBAAa,kCAAmC,SAAQ,cAAc,CACpE,OAAO,cAAc,EACrB,uCAAuC,EACvC,2CAA2C,CAC5C;;gBAWa,EACV,KAAU,EACV,SAAS,EACT,kBAAkB,EAClB,sBAAsB,EACtB,WAAW,EACX,2BAA2B,GAC5B,EAAE;QACD,KAAK,CAAC,EAAE,OAAO,CAAC,uCAAuC,CAAC,CAAC;QACzD,SAAS,EAAE,2CAA2C,CAAC;QACvD,kBAAkB,EAAE,0BAA0B,CAAC;QAC/C,sBAAsB,EAAE,GAAG,EAAE,CAAC;QAC9B,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC,CAAC;QAC9D,2BAA2B,EAAE,MAAM,CAAC;KACrC;IAwCK,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC7C,qBAAqB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA8D1E"}
@@ -0,0 +1,165 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ 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");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ 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");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _TokenSearchDiscoveryDataController_instances, _TokenSearchDiscoveryDataController_abortController, _TokenSearchDiscoveryDataController_tokenPricesService, _TokenSearchDiscoveryDataController_swapsSupportedChainIds, _TokenSearchDiscoveryDataController_fetchTokens, _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs, _TokenSearchDiscoveryDataController_fetchPriceData;
13
+ import { BaseController } from "@metamask/base-controller";
14
+ import { formatIconUrlWithProxy } from "../assetsUtil.mjs";
15
+ import { fetchTokenMetadata, TOKEN_METADATA_NO_SUPPORT_ERROR } from "../token-service.mjs";
16
+ // === GENERAL ===
17
+ export const controllerName = 'TokenSearchDiscoveryDataController';
18
+ export const MAX_TOKEN_DISPLAY_DATA_LENGTH = 10;
19
+ const tokenSearchDiscoveryDataControllerMetadata = {
20
+ tokenDisplayData: { persist: true, anonymous: false },
21
+ swapsTokenAddressesByChainId: { persist: true, anonymous: false },
22
+ };
23
+ /**
24
+ * Constructs the default {@link TokenSearchDiscoveryDataController} state. This allows
25
+ * consumers to provide a partial state object when initializing the controller
26
+ * and also helps in constructing complete state objects for this controller in
27
+ * tests.
28
+ *
29
+ * @returns The default {@link TokenSearchDiscoveryDataController} state.
30
+ */
31
+ export function getDefaultTokenSearchDiscoveryDataControllerState() {
32
+ return {
33
+ tokenDisplayData: [],
34
+ swapsTokenAddressesByChainId: {},
35
+ };
36
+ }
37
+ /**
38
+ * The TokenSearchDiscoveryDataController manages the retrieval of token search results and token discovery.
39
+ * It fetches token search results and discovery data from the Portfolio API.
40
+ */
41
+ export class TokenSearchDiscoveryDataController extends BaseController {
42
+ constructor({ state = {}, messenger, tokenPricesService, swapsSupportedChainIds, fetchTokens, fetchSwapsTokensThresholdMs, }) {
43
+ super({
44
+ name: controllerName,
45
+ metadata: tokenSearchDiscoveryDataControllerMetadata,
46
+ messenger,
47
+ state: {
48
+ ...getDefaultTokenSearchDiscoveryDataControllerState(),
49
+ ...state,
50
+ },
51
+ });
52
+ _TokenSearchDiscoveryDataController_instances.add(this);
53
+ _TokenSearchDiscoveryDataController_abortController.set(this, void 0);
54
+ _TokenSearchDiscoveryDataController_tokenPricesService.set(this, void 0);
55
+ _TokenSearchDiscoveryDataController_swapsSupportedChainIds.set(this, void 0);
56
+ _TokenSearchDiscoveryDataController_fetchTokens.set(this, void 0);
57
+ _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs.set(this, void 0);
58
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_abortController, new AbortController(), "f");
59
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_tokenPricesService, tokenPricesService, "f");
60
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_swapsSupportedChainIds, swapsSupportedChainIds, "f");
61
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_fetchTokens, fetchTokens, "f");
62
+ __classPrivateFieldSet(this, _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs, fetchSwapsTokensThresholdMs, "f");
63
+ }
64
+ async fetchSwapsTokens(chainId) {
65
+ if (!__classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_swapsSupportedChainIds, "f").includes(chainId)) {
66
+ return;
67
+ }
68
+ const swapsTokens = this.state.swapsTokenAddressesByChainId[chainId];
69
+ if ((!swapsTokens ||
70
+ swapsTokens.lastFetched <
71
+ Date.now() - __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs, "f")) &&
72
+ !swapsTokens?.isFetching) {
73
+ try {
74
+ this.update((state) => {
75
+ if (!state.swapsTokenAddressesByChainId[chainId]) {
76
+ state.swapsTokenAddressesByChainId[chainId] = {
77
+ lastFetched: Date.now(),
78
+ addresses: [],
79
+ isFetching: true,
80
+ };
81
+ }
82
+ else {
83
+ state.swapsTokenAddressesByChainId[chainId].isFetching = true;
84
+ }
85
+ });
86
+ const tokens = await __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_fetchTokens, "f").call(this, chainId);
87
+ this.update((state) => {
88
+ state.swapsTokenAddressesByChainId[chainId] = {
89
+ lastFetched: Date.now(),
90
+ addresses: tokens.map((token) => token.address),
91
+ isFetching: false,
92
+ };
93
+ });
94
+ }
95
+ catch (error) {
96
+ console.error(error);
97
+ }
98
+ }
99
+ }
100
+ async fetchTokenDisplayData(chainId, address) {
101
+ await this.fetchSwapsTokens(chainId);
102
+ let tokenMetadata;
103
+ try {
104
+ tokenMetadata = await fetchTokenMetadata(chainId, address, __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_abortController, "f").signal);
105
+ }
106
+ catch (error) {
107
+ if (!(error instanceof Error) ||
108
+ !error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)) {
109
+ throw error;
110
+ }
111
+ }
112
+ const { currentCurrency } = this.messagingSystem.call('CurrencyRateController:getState');
113
+ let tokenDisplayData;
114
+ if (!tokenMetadata) {
115
+ tokenDisplayData = {
116
+ found: false,
117
+ address,
118
+ chainId,
119
+ currency: currentCurrency,
120
+ };
121
+ }
122
+ else {
123
+ const priceData = await __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_instances, "m", _TokenSearchDiscoveryDataController_fetchPriceData).call(this, chainId, address);
124
+ tokenDisplayData = {
125
+ found: true,
126
+ address,
127
+ chainId,
128
+ currency: currentCurrency,
129
+ token: {
130
+ ...tokenMetadata,
131
+ isERC721: false,
132
+ image: formatIconUrlWithProxy({
133
+ chainId,
134
+ tokenAddress: address,
135
+ }),
136
+ },
137
+ price: priceData,
138
+ };
139
+ }
140
+ this.update((state) => {
141
+ state.tokenDisplayData = [
142
+ tokenDisplayData,
143
+ ...state.tokenDisplayData.filter((token) => token.address !== address ||
144
+ token.chainId !== chainId ||
145
+ token.currency !== currentCurrency),
146
+ ].slice(0, MAX_TOKEN_DISPLAY_DATA_LENGTH);
147
+ });
148
+ }
149
+ }
150
+ _TokenSearchDiscoveryDataController_abortController = new WeakMap(), _TokenSearchDiscoveryDataController_tokenPricesService = new WeakMap(), _TokenSearchDiscoveryDataController_swapsSupportedChainIds = new WeakMap(), _TokenSearchDiscoveryDataController_fetchTokens = new WeakMap(), _TokenSearchDiscoveryDataController_fetchSwapsTokensThresholdMs = new WeakMap(), _TokenSearchDiscoveryDataController_instances = new WeakSet(), _TokenSearchDiscoveryDataController_fetchPriceData = async function _TokenSearchDiscoveryDataController_fetchPriceData(chainId, address) {
151
+ const { currentCurrency } = this.messagingSystem.call('CurrencyRateController:getState');
152
+ try {
153
+ const pricesData = await __classPrivateFieldGet(this, _TokenSearchDiscoveryDataController_tokenPricesService, "f").fetchTokenPrices({
154
+ chainId,
155
+ tokenAddresses: [address],
156
+ currency: currentCurrency,
157
+ });
158
+ return pricesData[address] ?? null;
159
+ }
160
+ catch (error) {
161
+ console.error(error);
162
+ return null;
163
+ }
164
+ };
165
+ //# sourceMappingURL=TokenSearchDiscoveryDataController.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenSearchDiscoveryDataController.mjs","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport type { TokenDisplayData } from './types';\nimport { formatIconUrlWithProxy } from '../assetsUtil';\nimport type { GetCurrencyRateState } from '../CurrencyRateController';\nimport type { AbstractTokenPricesService } from '../token-prices-service';\nimport type { TokenPrice } from '../token-prices-service/abstract-token-prices-service';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from '../token-service';\nimport type { TokenListToken } from '../TokenListController';\n\n// === GENERAL ===\n\nexport const controllerName = 'TokenSearchDiscoveryDataController';\n\nexport const MAX_TOKEN_DISPLAY_DATA_LENGTH = 10;\n\n// === STATE ===\n\nexport type TokenSearchDiscoveryDataControllerState = {\n tokenDisplayData: TokenDisplayData[];\n swapsTokenAddressesByChainId: Record<\n Hex,\n { lastFetched: number; addresses: string[]; isFetching: boolean }\n >;\n};\n\nconst tokenSearchDiscoveryDataControllerMetadata = {\n tokenDisplayData: { persist: true, anonymous: false },\n swapsTokenAddressesByChainId: { persist: true, anonymous: false },\n} as const;\n\n// === MESSENGER ===\n\n/**\n * The action which can be used to retrieve the state of the\n * {@link TokenSearchDiscoveryDataController}.\n */\nexport type TokenSearchDiscoveryDataControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerState\n >;\n\n/**\n * All actions that {@link TokenSearchDiscoveryDataController} registers, to be\n * called externally.\n */\nexport type TokenSearchDiscoveryDataControllerActions =\n TokenSearchDiscoveryDataControllerGetStateAction;\n\n/**\n * All actions that {@link TokenSearchDiscoveryDataController} calls internally.\n */\nexport type AllowedActions = GetCurrencyRateState;\n\n/**\n * The event that {@link TokenSearchDiscoveryDataController} publishes when updating\n * state.\n */\nexport type TokenSearchDiscoveryDataControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerState\n >;\n\n/**\n * All events that {@link TokenSearchDiscoveryDataController} publishes, to be\n * subscribed to externally.\n */\nexport type TokenSearchDiscoveryDataControllerEvents =\n TokenSearchDiscoveryDataControllerStateChangeEvent;\n\n/**\n * All events that {@link TokenSearchDiscoveryDataController} subscribes to internally.\n */\nexport type AllowedEvents = never;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * {@link TokenSearchDiscoveryDataController}.\n */\nexport type TokenSearchDiscoveryDataControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerActions | AllowedActions,\n TokenSearchDiscoveryDataControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Constructs the default {@link TokenSearchDiscoveryDataController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link TokenSearchDiscoveryDataController} state.\n */\nexport function getDefaultTokenSearchDiscoveryDataControllerState(): TokenSearchDiscoveryDataControllerState {\n return {\n tokenDisplayData: [],\n swapsTokenAddressesByChainId: {},\n };\n}\n\n/**\n * The TokenSearchDiscoveryDataController manages the retrieval of token search results and token discovery.\n * It fetches token search results and discovery data from the Portfolio API.\n */\nexport class TokenSearchDiscoveryDataController extends BaseController<\n typeof controllerName,\n TokenSearchDiscoveryDataControllerState,\n TokenSearchDiscoveryDataControllerMessenger\n> {\n readonly #abortController: AbortController;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n readonly #swapsSupportedChainIds: Hex[];\n\n readonly #fetchTokens: (chainId: Hex) => Promise<{ address: string }[]>;\n\n readonly #fetchSwapsTokensThresholdMs: number;\n\n constructor({\n state = {},\n messenger,\n tokenPricesService,\n swapsSupportedChainIds,\n fetchTokens,\n fetchSwapsTokensThresholdMs,\n }: {\n state?: Partial<TokenSearchDiscoveryDataControllerState>;\n messenger: TokenSearchDiscoveryDataControllerMessenger;\n tokenPricesService: AbstractTokenPricesService;\n swapsSupportedChainIds: Hex[];\n fetchTokens: (chainId: Hex) => Promise<{ address: string }[]>;\n fetchSwapsTokensThresholdMs: number;\n }) {\n super({\n name: controllerName,\n metadata: tokenSearchDiscoveryDataControllerMetadata,\n messenger,\n state: {\n ...getDefaultTokenSearchDiscoveryDataControllerState(),\n ...state,\n },\n });\n\n this.#abortController = new AbortController();\n this.#tokenPricesService = tokenPricesService;\n this.#swapsSupportedChainIds = swapsSupportedChainIds;\n this.#fetchTokens = fetchTokens;\n this.#fetchSwapsTokensThresholdMs = fetchSwapsTokensThresholdMs;\n }\n\n async #fetchPriceData(\n chainId: Hex,\n address: string,\n ): Promise<TokenPrice<Hex, string> | null> {\n const { currentCurrency } = this.messagingSystem.call(\n 'CurrencyRateController:getState',\n );\n\n try {\n const pricesData = await this.#tokenPricesService.fetchTokenPrices({\n chainId,\n tokenAddresses: [address as Hex],\n currency: currentCurrency,\n });\n\n return pricesData[address as Hex] ?? null;\n } catch (error) {\n console.error(error);\n return null;\n }\n }\n\n async fetchSwapsTokens(chainId: Hex): Promise<void> {\n if (!this.#swapsSupportedChainIds.includes(chainId)) {\n return;\n }\n\n const swapsTokens = this.state.swapsTokenAddressesByChainId[chainId];\n if (\n (!swapsTokens ||\n swapsTokens.lastFetched <\n Date.now() - this.#fetchSwapsTokensThresholdMs) &&\n !swapsTokens?.isFetching\n ) {\n try {\n this.update((state) => {\n if (!state.swapsTokenAddressesByChainId[chainId]) {\n state.swapsTokenAddressesByChainId[chainId] = {\n lastFetched: Date.now(),\n addresses: [],\n isFetching: true,\n };\n } else {\n state.swapsTokenAddressesByChainId[chainId].isFetching = true;\n }\n });\n const tokens = await this.#fetchTokens(chainId);\n this.update((state) => {\n state.swapsTokenAddressesByChainId[chainId] = {\n lastFetched: Date.now(),\n addresses: tokens.map((token) => token.address),\n isFetching: false,\n };\n });\n } catch (error) {\n console.error(error);\n }\n }\n }\n\n async fetchTokenDisplayData(chainId: Hex, address: string): Promise<void> {\n await this.fetchSwapsTokens(chainId);\n\n let tokenMetadata: TokenListToken | undefined;\n try {\n tokenMetadata = await fetchTokenMetadata<TokenListToken>(\n chainId,\n address,\n this.#abortController.signal,\n );\n } catch (error) {\n if (\n !(error instanceof Error) ||\n !error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n throw error;\n }\n }\n\n const { currentCurrency } = this.messagingSystem.call(\n 'CurrencyRateController:getState',\n );\n\n let tokenDisplayData: TokenDisplayData;\n if (!tokenMetadata) {\n tokenDisplayData = {\n found: false,\n address,\n chainId,\n currency: currentCurrency,\n };\n } else {\n const priceData = await this.#fetchPriceData(chainId, address);\n tokenDisplayData = {\n found: true,\n address,\n chainId,\n currency: currentCurrency,\n token: {\n ...tokenMetadata,\n isERC721: false,\n image: formatIconUrlWithProxy({\n chainId,\n tokenAddress: address,\n }),\n },\n price: priceData,\n };\n }\n\n this.update((state) => {\n state.tokenDisplayData = [\n tokenDisplayData,\n ...state.tokenDisplayData.filter(\n (token) =>\n token.address !== address ||\n token.chainId !== chainId ||\n token.currency !== currentCurrency,\n ),\n ].slice(0, MAX_TOKEN_DISPLAY_DATA_LENGTH);\n });\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./TokenSearchDiscoveryDataController.cjs"), exports);
18
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2EAAqD","sourcesContent":["export * from './TokenSearchDiscoveryDataController';\nexport type * from './types';\n"]}
@@ -0,0 +1,3 @@
1
+ export * from "./TokenSearchDiscoveryDataController.cjs";
2
+ export type * from "./types.cjs";
3
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/index.ts"],"names":[],"mappings":"AAAA,yDAAqD;AACrD,iCAA6B"}
@@ -0,0 +1,3 @@
1
+ export * from "./TokenSearchDiscoveryDataController.mjs";
2
+ export type * from "./types.mjs";
3
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/index.ts"],"names":[],"mappings":"AAAA,yDAAqD;AACrD,iCAA6B"}
@@ -0,0 +1,2 @@
1
+ export * from "./TokenSearchDiscoveryDataController.mjs";
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/index.ts"],"names":[],"mappings":"AAAA,yDAAqD","sourcesContent":["export * from './TokenSearchDiscoveryDataController';\nexport type * from './types';\n"]}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../src/TokenSearchDiscoveryDataController/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nimport type { TokenPrice } from '../token-prices-service/abstract-token-prices-service';\nimport type { Token } from '../TokenRatesController';\n\nexport type NotFoundTokenDisplayData = {\n found: false;\n chainId: Hex;\n address: string;\n currency: string;\n};\n\nexport type FoundTokenDisplayData = {\n found: true;\n chainId: Hex;\n address: string;\n currency: string;\n token: Token;\n price: TokenPrice<Hex, string> | null;\n};\n\nexport type TokenDisplayData = NotFoundTokenDisplayData | FoundTokenDisplayData;\n"]}