@metamask-previews/bridge-controller 47.2.0-preview-5eac8e7 → 47.2.0-preview-a9d3cf8

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.
@@ -1,6 +1,5 @@
1
1
  import { StructError } from "@metamask/superstruct";
2
2
  import { Duration } from "@metamask/utils";
3
- import { fetchEventSource } from "@microsoft/fetch-event-source";
4
3
  import { isBitcoinChainId } from "./bridge.mjs";
5
4
  import { formatAddressToCaipReference, formatChainIdToDec } from "./caip-formatters.mjs";
6
5
  import { validateQuoteResponse, validateBitcoinQuoteResponse, validateSwapsTokenObject } from "./validators.mjs";
@@ -184,102 +183,4 @@ export const fetchAssetPrices = async (request) => {
184
183
  });
185
184
  return combinedPrices;
186
185
  };
187
- /**
188
- * Converts the generic quote request to the type that the bridge-api expects
189
- * then fetches quotes from the bridge-api
190
- *
191
- * @param fetchFn - The fetch function to use
192
- * @param request - The quote request
193
- * @param signal - The abort signal
194
- * @param clientId - The client ID for metrics
195
- * @param bridgeApiBaseUrl - The base URL for the bridge API
196
- * @param serverEventHandlers - The server event handlers
197
- * @param serverEventHandlers.onValidationFailures - The function to handle validation failures
198
- * @param serverEventHandlers.onValidQuotesReceived - The function to handle valid quotes
199
- * @param serverEventHandlers.onError - The function to handle errors
200
- * @returns A list of bridge tx quotes
201
- */
202
- export async function fetchBridgeQuoteStream(fetchFn, request, signal, clientId, bridgeApiBaseUrl, serverEventHandlers) {
203
- const destWalletAddress = request.destWalletAddress ?? request.walletAddress;
204
- // Transform the generic quote request into QuoteRequest
205
- const normalizedRequest = {
206
- walletAddress: formatAddressToCaipReference(request.walletAddress),
207
- destWalletAddress: formatAddressToCaipReference(destWalletAddress),
208
- srcChainId: formatChainIdToDec(request.srcChainId),
209
- destChainId: formatChainIdToDec(request.destChainId),
210
- srcTokenAddress: formatAddressToCaipReference(request.srcTokenAddress),
211
- destTokenAddress: formatAddressToCaipReference(request.destTokenAddress),
212
- srcTokenAmount: request.srcTokenAmount,
213
- insufficientBal: Boolean(request.insufficientBal),
214
- resetApproval: Boolean(request.resetApproval),
215
- gasIncluded: Boolean(request.gasIncluded),
216
- gasIncluded7702: Boolean(request.gasIncluded7702),
217
- };
218
- if (request.slippage !== undefined) {
219
- normalizedRequest.slippage = request.slippage;
220
- }
221
- if (request.noFee !== undefined) {
222
- normalizedRequest.noFee = request.noFee;
223
- }
224
- if (request.aggIds && request.aggIds.length > 0) {
225
- normalizedRequest.aggIds = request.aggIds;
226
- }
227
- if (request.bridgeIds && request.bridgeIds.length > 0) {
228
- normalizedRequest.bridgeIds = request.bridgeIds;
229
- }
230
- const queryParams = new URLSearchParams();
231
- Object.entries(normalizedRequest).forEach(([key, value]) => {
232
- queryParams.append(key, value.toString());
233
- });
234
- const onMessage = (event) => {
235
- console.log('===onmessage', event);
236
- const uniqueValidationFailures = new Set([]);
237
- if (event.data === '') {
238
- return;
239
- }
240
- const quoteResponse = JSON.parse(event.data);
241
- try {
242
- // TODO validate bitcoin quote
243
- validateQuoteResponse(quoteResponse);
244
- serverEventHandlers
245
- .onValidQuotesReceived([quoteResponse])
246
- .then((v) => {
247
- console.log('===onValidQuotesReceived success');
248
- return v;
249
- })
250
- .catch(() => {
251
- console.error('===onValidQuotesReceived error');
252
- });
253
- }
254
- catch (error) {
255
- if (error instanceof StructError) {
256
- error.failures().forEach(({ branch, path }) => {
257
- const aggregatorId = branch?.[0]?.quote?.bridgeId ||
258
- branch?.[0]?.quote?.bridges?.[0] ||
259
- quoteResponse?.quote?.bridgeId ||
260
- quoteResponse?.quote?.bridges?.[0] ||
261
- 'unknown';
262
- const pathString = path?.join('.') || 'unknown';
263
- uniqueValidationFailures.add([aggregatorId, pathString].join('|'));
264
- });
265
- }
266
- const validationFailures = Array.from(uniqueValidationFailures);
267
- if (uniqueValidationFailures.size > 0) {
268
- console.warn('Quote validation failed', validationFailures);
269
- serverEventHandlers.onValidationFailures(validationFailures);
270
- }
271
- }
272
- };
273
- const urlStream = `${bridgeApiBaseUrl}/getQuoteStream?${queryParams}`;
274
- await fetchEventSource(urlStream, {
275
- headers: getClientIdHeader(clientId),
276
- signal,
277
- onmessage: onMessage,
278
- onerror: serverEventHandlers.onError,
279
- // onclose: () => {
280
- // console.log('===onclose', 'should loading be set here?');
281
- // },
282
- // fetch: fetchFn,
283
- });
284
- }
285
186
  //# sourceMappingURL=fetch.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.mjs","sourceRoot":"","sources":["../../src/utils/fetch.ts"],"names":[],"mappings":"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","sourcesContent":["import { StructError } from '@metamask/superstruct';\nimport type { CaipAssetType, CaipChainId, Hex } from '@metamask/utils';\nimport { Duration } from '@metamask/utils';\nimport type { EventSourceMessage } from '@microsoft/fetch-event-source';\nimport { fetchEventSource } from '@microsoft/fetch-event-source';\n\nimport { isBitcoinChainId } from './bridge';\nimport {\n formatAddressToCaipReference,\n formatChainIdToDec,\n} from './caip-formatters';\nimport type { FeatureId } from './validators';\nimport {\n validateQuoteResponse,\n validateBitcoinQuoteResponse,\n validateSwapsTokenObject,\n} from './validators';\nimport type {\n QuoteResponse,\n FetchFunction,\n GenericQuoteRequest,\n QuoteRequest,\n BridgeAsset,\n} from '../types';\n\nconst CACHE_REFRESH_TEN_MINUTES = 10 * Duration.Minute;\n\nexport const getClientIdHeader = (clientId: string) => ({\n 'X-Client-Id': clientId,\n});\n\n/**\n * Returns a list of enabled (unblocked) tokens\n *\n * @param chainId - The chain ID to fetch tokens for\n * @param clientId - The client ID for metrics\n * @param fetchFn - The fetch function to use\n * @param bridgeApiBaseUrl - The base URL for the bridge API\n * @returns A list of enabled (unblocked) tokens\n */\nexport async function fetchBridgeTokens(\n chainId: Hex | CaipChainId,\n clientId: string,\n fetchFn: FetchFunction,\n bridgeApiBaseUrl: string,\n): Promise<Record<string, BridgeAsset>> {\n // TODO make token api v2 call\n const url = `${bridgeApiBaseUrl}/getTokens?chainId=${formatChainIdToDec(chainId)}`;\n\n // TODO we will need to cache these. In Extension fetchWithCache is used. This is due to the following:\n // If we allow selecting dest networks which the user has not imported,\n // note that the Assets controller won't be able to provide tokens. In extension we fetch+cache the token list from bridge-api to handle this\n const tokens = await fetchFn(url, {\n headers: getClientIdHeader(clientId),\n cacheOptions: { cacheRefreshTime: CACHE_REFRESH_TEN_MINUTES },\n functionName: 'fetchBridgeTokens',\n });\n\n const transformedTokens: Record<string, BridgeAsset> = {};\n tokens.forEach((token: unknown) => {\n if (validateSwapsTokenObject(token)) {\n transformedTokens[token.address] = token;\n }\n });\n return transformedTokens;\n}\n\n/**\n * Converts the generic quote request to the type that the bridge-api expects\n * then fetches quotes from the bridge-api\n *\n * @param request - The quote request\n * @param signal - The abort signal\n * @param clientId - The client ID for metrics\n * @param fetchFn - The fetch function to use\n * @param bridgeApiBaseUrl - The base URL for the bridge API\n * @param featureId - The feature ID to append to each quote\n * @returns A list of bridge tx quotes\n */\nexport async function fetchBridgeQuotes(\n request: GenericQuoteRequest,\n signal: AbortSignal | null,\n clientId: string,\n fetchFn: FetchFunction,\n bridgeApiBaseUrl: string,\n featureId: FeatureId | null,\n): Promise<{\n quotes: QuoteResponse[];\n validationFailures: string[];\n}> {\n const destWalletAddress = request.destWalletAddress ?? request.walletAddress;\n // Transform the generic quote request into QuoteRequest\n const normalizedRequest: QuoteRequest = {\n walletAddress: formatAddressToCaipReference(request.walletAddress),\n destWalletAddress: formatAddressToCaipReference(destWalletAddress),\n srcChainId: formatChainIdToDec(request.srcChainId),\n destChainId: formatChainIdToDec(request.destChainId),\n srcTokenAddress: formatAddressToCaipReference(request.srcTokenAddress),\n destTokenAddress: formatAddressToCaipReference(request.destTokenAddress),\n srcTokenAmount: request.srcTokenAmount,\n insufficientBal: Boolean(request.insufficientBal),\n resetApproval: Boolean(request.resetApproval),\n gasIncluded: Boolean(request.gasIncluded),\n gasIncluded7702: Boolean(request.gasIncluded7702),\n };\n if (request.slippage !== undefined) {\n normalizedRequest.slippage = request.slippage;\n }\n if (request.noFee !== undefined) {\n normalizedRequest.noFee = request.noFee;\n }\n if (request.aggIds && request.aggIds.length > 0) {\n normalizedRequest.aggIds = request.aggIds;\n }\n if (request.bridgeIds && request.bridgeIds.length > 0) {\n normalizedRequest.bridgeIds = request.bridgeIds;\n }\n\n const queryParams = new URLSearchParams();\n Object.entries(normalizedRequest).forEach(([key, value]) => {\n queryParams.append(key, value.toString());\n });\n const url = `${bridgeApiBaseUrl}/getQuote?${queryParams}`;\n const quotes: unknown[] = await fetchFn(url, {\n headers: getClientIdHeader(clientId),\n signal,\n cacheOptions: { cacheRefreshTime: 0 },\n functionName: 'fetchBridgeQuotes',\n });\n\n const uniqueValidationFailures: Set<string> = new Set<string>([]);\n const filteredQuotes = quotes\n .filter((quoteResponse: unknown): quoteResponse is QuoteResponse => {\n try {\n const isBitcoinQuote = isBitcoinChainId(request.srcChainId);\n\n if (isBitcoinQuote) {\n return validateBitcoinQuoteResponse(quoteResponse);\n }\n return validateQuoteResponse(quoteResponse);\n } catch (error) {\n if (error instanceof StructError) {\n error.failures().forEach(({ branch, path }) => {\n const aggregatorId =\n branch?.[0]?.quote?.bridgeId ||\n branch?.[0]?.quote?.bridges?.[0] ||\n (quoteResponse as QuoteResponse)?.quote?.bridgeId ||\n (quoteResponse as QuoteResponse)?.quote?.bridges?.[0] ||\n 'unknown';\n const pathString = path?.join('.') || 'unknown';\n uniqueValidationFailures.add([aggregatorId, pathString].join('|'));\n });\n }\n return false;\n }\n })\n .map((quote) => ({\n ...quote,\n featureId: featureId ?? undefined,\n }));\n\n const validationFailures = Array.from(uniqueValidationFailures);\n if (uniqueValidationFailures.size > 0) {\n console.warn('Quote validation failed', validationFailures);\n }\n\n return {\n quotes: filteredQuotes,\n validationFailures,\n };\n}\n\nconst fetchAssetPricesForCurrency = async (request: {\n currency: string;\n assetIds: Set<CaipAssetType>;\n clientId: string;\n fetchFn: FetchFunction;\n}): Promise<Record<CaipAssetType, { [currency: string]: string }>> => {\n const { currency, assetIds, clientId, fetchFn } = request;\n const validAssetIds = Array.from(assetIds).filter(Boolean);\n if (validAssetIds.length === 0) {\n return {};\n }\n\n const queryParams = new URLSearchParams({\n assetIds: validAssetIds.filter(Boolean).join(','),\n vsCurrency: currency,\n });\n const url = `https://price.api.cx.metamask.io/v3/spot-prices?${queryParams}`;\n const priceApiResponse = (await fetchFn(url, {\n headers: getClientIdHeader(clientId),\n cacheOptions: { cacheRefreshTime: Number(Duration.Second * 30) },\n functionName: 'fetchAssetExchangeRates',\n })) as Record<CaipAssetType, { [currency: string]: number }>;\n\n if (!priceApiResponse || typeof priceApiResponse !== 'object') {\n return {};\n }\n\n return Object.entries(priceApiResponse).reduce(\n (acc, [assetId, currencyToPrice]) => {\n if (!currencyToPrice) {\n return acc;\n }\n if (!acc[assetId as CaipAssetType]) {\n acc[assetId as CaipAssetType] = {};\n }\n if (currencyToPrice[currency]) {\n acc[assetId as CaipAssetType][currency] =\n currencyToPrice[currency].toString();\n }\n return acc;\n },\n {} as Record<CaipAssetType, { [currency: string]: string }>,\n );\n};\n\n/**\n * Fetches the asset prices from the price API for multiple currencies\n *\n * @param request - The request object\n * @returns The asset prices by assetId\n */\nexport const fetchAssetPrices = async (\n request: {\n currencies: Set<string>;\n } & Omit<Parameters<typeof fetchAssetPricesForCurrency>[0], 'currency'>,\n): Promise<\n Record<CaipAssetType, { [currency: string]: string } | undefined>\n> => {\n const { currencies, ...args } = request;\n\n const combinedPrices = await Promise.allSettled(\n Array.from(currencies).map(\n async (currency) =>\n await fetchAssetPricesForCurrency({ ...args, currency }),\n ),\n ).then((priceApiResponse) => {\n return priceApiResponse.reduce(\n (acc, result) => {\n if (result.status === 'fulfilled') {\n Object.entries(result.value).forEach(([assetId, currencyToPrice]) => {\n const existingPrices = acc[assetId as CaipAssetType];\n if (!existingPrices) {\n acc[assetId as CaipAssetType] = {};\n }\n Object.entries(currencyToPrice).forEach(([currency, price]) => {\n acc[assetId as CaipAssetType][currency] = price;\n });\n });\n }\n return acc;\n },\n {} as Record<CaipAssetType, { [currency: string]: string }>,\n );\n });\n\n return combinedPrices;\n};\n\n/**\n * Converts the generic quote request to the type that the bridge-api expects\n * then fetches quotes from the bridge-api\n *\n * @param fetchFn - The fetch function to use\n * @param request - The quote request\n * @param signal - The abort signal\n * @param clientId - The client ID for metrics\n * @param bridgeApiBaseUrl - The base URL for the bridge API\n * @param serverEventHandlers - The server event handlers\n * @param serverEventHandlers.onValidationFailures - The function to handle validation failures\n * @param serverEventHandlers.onValidQuotesReceived - The function to handle valid quotes\n * @param serverEventHandlers.onError - The function to handle errors\n * @returns A list of bridge tx quotes\n */\nexport async function fetchBridgeQuoteStream(\n fetchFn: FetchFunction,\n request: GenericQuoteRequest,\n signal: AbortSignal | null,\n clientId: string,\n bridgeApiBaseUrl: string,\n serverEventHandlers: {\n onValidationFailures: (validationFailures: string[]) => void;\n onValidQuotesReceived: (quotes: QuoteResponse[]) => Promise<void>;\n onError?: (event: Error) => void;\n },\n): Promise<void> {\n const destWalletAddress = request.destWalletAddress ?? request.walletAddress;\n // Transform the generic quote request into QuoteRequest\n const normalizedRequest: QuoteRequest = {\n walletAddress: formatAddressToCaipReference(request.walletAddress),\n destWalletAddress: formatAddressToCaipReference(destWalletAddress),\n srcChainId: formatChainIdToDec(request.srcChainId),\n destChainId: formatChainIdToDec(request.destChainId),\n srcTokenAddress: formatAddressToCaipReference(request.srcTokenAddress),\n destTokenAddress: formatAddressToCaipReference(request.destTokenAddress),\n srcTokenAmount: request.srcTokenAmount,\n insufficientBal: Boolean(request.insufficientBal),\n resetApproval: Boolean(request.resetApproval),\n gasIncluded: Boolean(request.gasIncluded),\n gasIncluded7702: Boolean(request.gasIncluded7702),\n };\n if (request.slippage !== undefined) {\n normalizedRequest.slippage = request.slippage;\n }\n if (request.noFee !== undefined) {\n normalizedRequest.noFee = request.noFee;\n }\n if (request.aggIds && request.aggIds.length > 0) {\n normalizedRequest.aggIds = request.aggIds;\n }\n if (request.bridgeIds && request.bridgeIds.length > 0) {\n normalizedRequest.bridgeIds = request.bridgeIds;\n }\n\n const queryParams = new URLSearchParams();\n Object.entries(normalizedRequest).forEach(([key, value]) => {\n queryParams.append(key, value.toString());\n });\n\n const onMessage = (event: EventSourceMessage) => {\n console.log('===onmessage', event);\n const uniqueValidationFailures: Set<string> = new Set<string>([]);\n if (event.data === '') {\n return;\n }\n const quoteResponse = JSON.parse(event.data);\n\n try {\n // TODO validate bitcoin quote\n validateQuoteResponse(quoteResponse);\n\n serverEventHandlers\n .onValidQuotesReceived([quoteResponse])\n .then((v) => {\n console.log('===onValidQuotesReceived success');\n return v;\n })\n .catch(() => {\n console.error('===onValidQuotesReceived error');\n });\n } catch (error) {\n if (error instanceof StructError) {\n error.failures().forEach(({ branch, path }) => {\n const aggregatorId =\n branch?.[0]?.quote?.bridgeId ||\n branch?.[0]?.quote?.bridges?.[0] ||\n (quoteResponse as QuoteResponse)?.quote?.bridgeId ||\n (quoteResponse as QuoteResponse)?.quote?.bridges?.[0] ||\n 'unknown';\n const pathString = path?.join('.') || 'unknown';\n uniqueValidationFailures.add([aggregatorId, pathString].join('|'));\n });\n }\n const validationFailures = Array.from(uniqueValidationFailures);\n if (uniqueValidationFailures.size > 0) {\n console.warn('Quote validation failed', validationFailures);\n serverEventHandlers.onValidationFailures(validationFailures);\n }\n }\n };\n\n const urlStream = `${bridgeApiBaseUrl}/getQuoteStream?${queryParams}`;\n await fetchEventSource(urlStream, {\n headers: getClientIdHeader(clientId),\n signal,\n onmessage: onMessage,\n onerror: serverEventHandlers.onError,\n // onclose: () => {\n // console.log('===onclose', 'should loading be set here?');\n // },\n // fetch: fetchFn,\n });\n}\n"]}
1
+ {"version":3,"file":"fetch.mjs","sourceRoot":"","sources":["../../src/utils/fetch.ts"],"names":[],"mappings":"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","sourcesContent":["import { StructError } from '@metamask/superstruct';\nimport type { CaipAssetType, CaipChainId, Hex } from '@metamask/utils';\nimport { Duration } from '@metamask/utils';\n\nimport { isBitcoinChainId } from './bridge';\nimport {\n formatAddressToCaipReference,\n formatChainIdToDec,\n} from './caip-formatters';\nimport type { FeatureId } from './validators';\nimport {\n validateQuoteResponse,\n validateBitcoinQuoteResponse,\n validateSwapsTokenObject,\n} from './validators';\nimport type {\n QuoteResponse,\n FetchFunction,\n GenericQuoteRequest,\n QuoteRequest,\n BridgeAsset,\n} from '../types';\n\nconst CACHE_REFRESH_TEN_MINUTES = 10 * Duration.Minute;\n\nexport const getClientIdHeader = (clientId: string) => ({\n 'X-Client-Id': clientId,\n});\n\n/**\n * Returns a list of enabled (unblocked) tokens\n *\n * @param chainId - The chain ID to fetch tokens for\n * @param clientId - The client ID for metrics\n * @param fetchFn - The fetch function to use\n * @param bridgeApiBaseUrl - The base URL for the bridge API\n * @returns A list of enabled (unblocked) tokens\n */\nexport async function fetchBridgeTokens(\n chainId: Hex | CaipChainId,\n clientId: string,\n fetchFn: FetchFunction,\n bridgeApiBaseUrl: string,\n): Promise<Record<string, BridgeAsset>> {\n // TODO make token api v2 call\n const url = `${bridgeApiBaseUrl}/getTokens?chainId=${formatChainIdToDec(chainId)}`;\n\n // TODO we will need to cache these. In Extension fetchWithCache is used. This is due to the following:\n // If we allow selecting dest networks which the user has not imported,\n // note that the Assets controller won't be able to provide tokens. In extension we fetch+cache the token list from bridge-api to handle this\n const tokens = await fetchFn(url, {\n headers: getClientIdHeader(clientId),\n cacheOptions: { cacheRefreshTime: CACHE_REFRESH_TEN_MINUTES },\n functionName: 'fetchBridgeTokens',\n });\n\n const transformedTokens: Record<string, BridgeAsset> = {};\n tokens.forEach((token: unknown) => {\n if (validateSwapsTokenObject(token)) {\n transformedTokens[token.address] = token;\n }\n });\n return transformedTokens;\n}\n\n/**\n * Converts the generic quote request to the type that the bridge-api expects\n * then fetches quotes from the bridge-api\n *\n * @param request - The quote request\n * @param signal - The abort signal\n * @param clientId - The client ID for metrics\n * @param fetchFn - The fetch function to use\n * @param bridgeApiBaseUrl - The base URL for the bridge API\n * @param featureId - The feature ID to append to each quote\n * @returns A list of bridge tx quotes\n */\nexport async function fetchBridgeQuotes(\n request: GenericQuoteRequest,\n signal: AbortSignal | null,\n clientId: string,\n fetchFn: FetchFunction,\n bridgeApiBaseUrl: string,\n featureId: FeatureId | null,\n): Promise<{\n quotes: QuoteResponse[];\n validationFailures: string[];\n}> {\n const destWalletAddress = request.destWalletAddress ?? request.walletAddress;\n // Transform the generic quote request into QuoteRequest\n const normalizedRequest: QuoteRequest = {\n walletAddress: formatAddressToCaipReference(request.walletAddress),\n destWalletAddress: formatAddressToCaipReference(destWalletAddress),\n srcChainId: formatChainIdToDec(request.srcChainId),\n destChainId: formatChainIdToDec(request.destChainId),\n srcTokenAddress: formatAddressToCaipReference(request.srcTokenAddress),\n destTokenAddress: formatAddressToCaipReference(request.destTokenAddress),\n srcTokenAmount: request.srcTokenAmount,\n insufficientBal: Boolean(request.insufficientBal),\n resetApproval: Boolean(request.resetApproval),\n gasIncluded: Boolean(request.gasIncluded),\n gasIncluded7702: Boolean(request.gasIncluded7702),\n };\n if (request.slippage !== undefined) {\n normalizedRequest.slippage = request.slippage;\n }\n if (request.noFee !== undefined) {\n normalizedRequest.noFee = request.noFee;\n }\n if (request.aggIds && request.aggIds.length > 0) {\n normalizedRequest.aggIds = request.aggIds;\n }\n if (request.bridgeIds && request.bridgeIds.length > 0) {\n normalizedRequest.bridgeIds = request.bridgeIds;\n }\n\n const queryParams = new URLSearchParams();\n Object.entries(normalizedRequest).forEach(([key, value]) => {\n queryParams.append(key, value.toString());\n });\n const url = `${bridgeApiBaseUrl}/getQuote?${queryParams}`;\n const quotes: unknown[] = await fetchFn(url, {\n headers: getClientIdHeader(clientId),\n signal,\n cacheOptions: { cacheRefreshTime: 0 },\n functionName: 'fetchBridgeQuotes',\n });\n\n const uniqueValidationFailures: Set<string> = new Set<string>([]);\n const filteredQuotes = quotes\n .filter((quoteResponse: unknown): quoteResponse is QuoteResponse => {\n try {\n const isBitcoinQuote = isBitcoinChainId(request.srcChainId);\n\n if (isBitcoinQuote) {\n return validateBitcoinQuoteResponse(quoteResponse);\n }\n return validateQuoteResponse(quoteResponse);\n } catch (error) {\n if (error instanceof StructError) {\n error.failures().forEach(({ branch, path }) => {\n const aggregatorId =\n branch?.[0]?.quote?.bridgeId ||\n branch?.[0]?.quote?.bridges?.[0] ||\n (quoteResponse as QuoteResponse)?.quote?.bridgeId ||\n (quoteResponse as QuoteResponse)?.quote?.bridges?.[0] ||\n 'unknown';\n const pathString = path?.join('.') || 'unknown';\n uniqueValidationFailures.add([aggregatorId, pathString].join('|'));\n });\n }\n return false;\n }\n })\n .map((quote) => ({\n ...quote,\n featureId: featureId ?? undefined,\n }));\n\n const validationFailures = Array.from(uniqueValidationFailures);\n if (uniqueValidationFailures.size > 0) {\n console.warn('Quote validation failed', validationFailures);\n }\n\n return {\n quotes: filteredQuotes,\n validationFailures,\n };\n}\n\nconst fetchAssetPricesForCurrency = async (request: {\n currency: string;\n assetIds: Set<CaipAssetType>;\n clientId: string;\n fetchFn: FetchFunction;\n}): Promise<Record<CaipAssetType, { [currency: string]: string }>> => {\n const { currency, assetIds, clientId, fetchFn } = request;\n const validAssetIds = Array.from(assetIds).filter(Boolean);\n if (validAssetIds.length === 0) {\n return {};\n }\n\n const queryParams = new URLSearchParams({\n assetIds: validAssetIds.filter(Boolean).join(','),\n vsCurrency: currency,\n });\n const url = `https://price.api.cx.metamask.io/v3/spot-prices?${queryParams}`;\n const priceApiResponse = (await fetchFn(url, {\n headers: getClientIdHeader(clientId),\n cacheOptions: { cacheRefreshTime: Number(Duration.Second * 30) },\n functionName: 'fetchAssetExchangeRates',\n })) as Record<CaipAssetType, { [currency: string]: number }>;\n\n if (!priceApiResponse || typeof priceApiResponse !== 'object') {\n return {};\n }\n\n return Object.entries(priceApiResponse).reduce(\n (acc, [assetId, currencyToPrice]) => {\n if (!currencyToPrice) {\n return acc;\n }\n if (!acc[assetId as CaipAssetType]) {\n acc[assetId as CaipAssetType] = {};\n }\n if (currencyToPrice[currency]) {\n acc[assetId as CaipAssetType][currency] =\n currencyToPrice[currency].toString();\n }\n return acc;\n },\n {} as Record<CaipAssetType, { [currency: string]: string }>,\n );\n};\n\n/**\n * Fetches the asset prices from the price API for multiple currencies\n *\n * @param request - The request object\n * @returns The asset prices by assetId\n */\nexport const fetchAssetPrices = async (\n request: {\n currencies: Set<string>;\n } & Omit<Parameters<typeof fetchAssetPricesForCurrency>[0], 'currency'>,\n): Promise<\n Record<CaipAssetType, { [currency: string]: string } | undefined>\n> => {\n const { currencies, ...args } = request;\n\n const combinedPrices = await Promise.allSettled(\n Array.from(currencies).map(\n async (currency) =>\n await fetchAssetPricesForCurrency({ ...args, currency }),\n ),\n ).then((priceApiResponse) => {\n return priceApiResponse.reduce(\n (acc, result) => {\n if (result.status === 'fulfilled') {\n Object.entries(result.value).forEach(([assetId, currencyToPrice]) => {\n const existingPrices = acc[assetId as CaipAssetType];\n if (!existingPrices) {\n acc[assetId as CaipAssetType] = {};\n }\n Object.entries(currencyToPrice).forEach(([currency, price]) => {\n acc[assetId as CaipAssetType][currency] = price;\n });\n });\n }\n return acc;\n },\n {} as Record<CaipAssetType, { [currency: string]: string }>,\n );\n });\n\n return combinedPrices;\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/bridge-controller",
3
- "version": "47.2.0-preview-5eac8e7",
3
+ "version": "47.2.0-preview-a9d3cf8",
4
4
  "description": "Manages bridge-related quote fetching functionality for MetaMask",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -60,7 +60,6 @@
60
60
  "@metamask/multichain-network-controller": "^1.0.0",
61
61
  "@metamask/polling-controller": "^14.0.0",
62
62
  "@metamask/utils": "^11.8.1",
63
- "@microsoft/fetch-event-source": "^2.0.1",
64
63
  "bignumber.js": "^9.1.2",
65
64
  "reselect": "^5.1.1",
66
65
  "uuid": "^8.3.2"