@metamask/bridge-controller 55.0.0 → 56.0.1

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 (42) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/dist/bridge-controller.cjs +29 -29
  3. package/dist/bridge-controller.cjs.map +1 -1
  4. package/dist/bridge-controller.d.cts.map +1 -1
  5. package/dist/bridge-controller.d.mts.map +1 -1
  6. package/dist/bridge-controller.mjs +29 -29
  7. package/dist/bridge-controller.mjs.map +1 -1
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +2 -2
  10. package/dist/index.d.cts.map +1 -1
  11. package/dist/index.d.mts +2 -2
  12. package/dist/index.d.mts.map +1 -1
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/selectors.d.cts +3805 -3805
  15. package/dist/selectors.d.mts +3805 -3805
  16. package/dist/types.cjs.map +1 -1
  17. package/dist/types.d.cts +7 -4
  18. package/dist/types.d.cts.map +1 -1
  19. package/dist/types.d.mts +7 -4
  20. package/dist/types.d.mts.map +1 -1
  21. package/dist/types.mjs.map +1 -1
  22. package/dist/utils/bridge.d.cts +3 -3
  23. package/dist/utils/bridge.d.mts +3 -3
  24. package/dist/utils/feature-flags.d.cts +3 -3
  25. package/dist/utils/feature-flags.d.mts +3 -3
  26. package/dist/utils/fetch-server-events.cjs +10 -1
  27. package/dist/utils/fetch-server-events.cjs.map +1 -1
  28. package/dist/utils/fetch-server-events.d.cts.map +1 -1
  29. package/dist/utils/fetch-server-events.d.mts.map +1 -1
  30. package/dist/utils/fetch-server-events.mjs +10 -1
  31. package/dist/utils/fetch-server-events.mjs.map +1 -1
  32. package/dist/utils/quote-fees.cjs +26 -6
  33. package/dist/utils/quote-fees.cjs.map +1 -1
  34. package/dist/utils/quote-fees.d.cts.map +1 -1
  35. package/dist/utils/quote-fees.d.mts.map +1 -1
  36. package/dist/utils/quote-fees.mjs +26 -6
  37. package/dist/utils/quote-fees.mjs.map +1 -1
  38. package/dist/utils/slippage.d.cts +1 -1
  39. package/dist/utils/slippage.d.mts +1 -1
  40. package/dist/utils/validators.d.cts +347 -347
  41. package/dist/utils/validators.d.mts +347 -347
  42. package/package.json +16 -15
@@ -75,18 +75,38 @@ const appendNonEvmFees = async (quotes, messenger, selectedAccount) => {
75
75
  }
76
76
  const nonEvmFeePromises = Promise.allSettled(quotes.map(async (quoteResponse) => {
77
77
  const { trade, quote } = quoteResponse;
78
- if (selectedAccount?.metadata?.snap?.id && typeof trade === 'string') {
78
+ // Skip fee computation if no snap account or trade data
79
+ if (!selectedAccount?.metadata?.snap?.id || !trade) {
80
+ return quoteResponse;
81
+ }
82
+ try {
79
83
  const scope = formatChainIdToCaip(quote.srcChainId);
80
- const response = (await messenger.call('SnapController:handleRequest', computeFeeRequest(selectedAccount.metadata.snap?.id, trade, selectedAccount.id, scope)));
81
- const baseFee = response?.find((fee) => fee.type === 'base');
82
- // Store fees in native units as returned by the snap (e.g., SOL, BTC)
83
- const feeInNative = baseFee?.asset?.amount || '0';
84
+ // Normalize trade data to string format expected by snap
85
+ // Solana: trade is already a base64 transaction string
86
+ // Bitcoin: extract unsignedPsbtBase64 from trade object
87
+ const transaction = typeof trade === 'string'
88
+ ? trade
89
+ : trade.unsignedPsbtBase64;
90
+ const response = (await messenger.call('SnapController:handleRequest', computeFeeRequest(selectedAccount.metadata.snap?.id, transaction, selectedAccount.id, scope)));
91
+ // Bitcoin snap returns 'priority' fee, Solana returns 'base' fee
92
+ const fee = response?.find((f) => f.type === 'base') ||
93
+ response?.find((f) => f.type === 'priority') ||
94
+ response?.[0];
95
+ const feeInNative = fee?.asset?.amount || '0';
84
96
  return {
85
97
  ...quoteResponse,
86
98
  nonEvmFeesInNative: feeInNative,
87
99
  };
88
100
  }
89
- return quoteResponse;
101
+ catch (error) {
102
+ // Return quote with undefined fee if snap fails (e.g., insufficient UTXO funds)
103
+ // Client can render special UI or skip the quote card row for quotes with missing fee data
104
+ console.error(`Failed to compute non-EVM fees for quote ${quote.requestId}:`, error);
105
+ return {
106
+ ...quoteResponse,
107
+ nonEvmFeesInNative: undefined,
108
+ };
109
+ }
90
110
  }));
91
111
  const quotesWithNonEvmFees = (await nonEvmFeePromises).reduce((acc, result) => {
92
112
  if (result.status === 'fulfilled' && result.value) {
@@ -1 +1 @@
1
- {"version":3,"file":"quote-fees.mjs","sourceRoot":"","sources":["../../src/utils/quote-fees.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { TransactionController } from '@metamask/transaction-controller';\nimport { numberToHex } from '@metamask/utils';\n\nimport { isNonEvmChainId, sumHexes } from './bridge';\nimport { formatChainIdToCaip } from './caip-formatters';\nimport { computeFeeRequest } from './snaps';\nimport { CHAIN_IDS } from '../constants/chains';\nimport type {\n QuoteResponse,\n L1GasFees,\n NonEvmFees,\n TxData,\n BridgeControllerMessenger,\n} from '../types';\n\n/**\n * Appends transaction fees for EVM chains to quotes\n *\n * @param quotes - Array of quote responses to append fees to\n * @param getLayer1GasFee - The function to use to get the layer 1 gas fee\n * @returns Array of quotes with fees appended, or undefined if quotes are for non-EVM chains\n */\nconst appendL1GasFees = async (\n quotes: QuoteResponse[],\n getLayer1GasFee: typeof TransactionController.prototype.getLayer1GasFee,\n): Promise<(QuoteResponse & L1GasFees)[] | undefined> => {\n // Indicates whether some of the quotes are not for optimism or base\n const hasInvalidQuotes = quotes.some(({ quote }) => {\n const chainId = formatChainIdToCaip(quote.srcChainId);\n return ![CHAIN_IDS.OPTIMISM, CHAIN_IDS.BASE]\n .map(formatChainIdToCaip)\n .includes(chainId);\n });\n\n // Only append L1 gas fees if all quotes are for either optimism or base\n if (hasInvalidQuotes) {\n return undefined;\n }\n\n const l1GasFeePromises = Promise.allSettled(\n quotes.map(async (quoteResponse) => {\n const { quote, trade, approval } = quoteResponse;\n const chainId = numberToHex(quote.srcChainId);\n\n const getTxParams = (txData: TxData) => ({\n from: txData.from,\n to: txData.to,\n value: txData.value,\n data: txData.data,\n gasLimit: txData.gasLimit?.toString(),\n });\n const approvalL1GasFees = approval\n ? await getLayer1GasFee({\n transactionParams: getTxParams(approval),\n chainId,\n })\n : '0x0';\n const tradeL1GasFees = await getLayer1GasFee({\n transactionParams: getTxParams(trade as TxData),\n chainId,\n });\n\n if (approvalL1GasFees === undefined || tradeL1GasFees === undefined) {\n return undefined;\n }\n\n return {\n ...quoteResponse,\n l1GasFeesInHexWei: sumHexes(approvalL1GasFees, tradeL1GasFees),\n };\n }),\n );\n\n const quotesWithL1GasFees = (await l1GasFeePromises).reduce<\n (QuoteResponse & L1GasFees)[]\n >((acc, result) => {\n if (result.status === 'fulfilled' && result.value) {\n acc.push(result.value);\n } else if (result.status === 'rejected') {\n console.error('Error calculating L1 gas fees for quote', result.reason);\n }\n return acc;\n }, []);\n\n return quotesWithL1GasFees;\n};\n\n/**\n * Appends transaction fees for non-EVM chains to quotes\n *\n * @param quotes - Array of quote responses to append fees to\n * @param messenger - The messaging system to use to call the snap controller\n * @param selectedAccount - The selected account for which the quotes were requested\n * @returns Array of quotes with fees appended, or undefined if quotes are for EVM chains\n */\nconst appendNonEvmFees = async (\n quotes: QuoteResponse[],\n messenger: BridgeControllerMessenger,\n selectedAccount: InternalAccount,\n): Promise<(QuoteResponse & NonEvmFees)[] | undefined> => {\n if (\n quotes.some(({ quote: { srcChainId } }) => !isNonEvmChainId(srcChainId))\n ) {\n return undefined;\n }\n\n const nonEvmFeePromises = Promise.allSettled(\n quotes.map(async (quoteResponse) => {\n const { trade, quote } = quoteResponse;\n\n if (selectedAccount?.metadata?.snap?.id && typeof trade === 'string') {\n const scope = formatChainIdToCaip(quote.srcChainId);\n\n const response = (await messenger.call(\n 'SnapController:handleRequest',\n computeFeeRequest(\n selectedAccount.metadata.snap?.id,\n trade,\n selectedAccount.id,\n scope,\n ),\n )) as {\n type: 'base' | 'priority';\n asset: {\n unit: string;\n type: string;\n amount: string;\n fungible: true;\n };\n }[];\n\n const baseFee = response?.find((fee) => fee.type === 'base');\n // Store fees in native units as returned by the snap (e.g., SOL, BTC)\n const feeInNative = baseFee?.asset?.amount || '0';\n\n return {\n ...quoteResponse,\n nonEvmFeesInNative: feeInNative,\n };\n }\n return quoteResponse;\n }),\n );\n\n const quotesWithNonEvmFees = (await nonEvmFeePromises).reduce<\n (QuoteResponse & NonEvmFees)[]\n >((acc, result) => {\n if (result.status === 'fulfilled' && result.value) {\n acc.push(result.value);\n } else if (result.status === 'rejected') {\n console.error('Error calculating non-EVM fees for quote', result.reason);\n }\n return acc;\n }, []);\n\n return quotesWithNonEvmFees;\n};\n\n/**\n * Appends transaction fees to quotes\n *\n * @param quotes - Array of quote responses to append fees to\n * @param messenger - The bridge controller to use to call the snap controller\n * @param getLayer1GasFee - The function to use to get the layer 1 gas fee\n * @param selectedAccount - The selected account for which the quotes were requested\n * @returns Array of quotes with fees appended, or undefined if quotes are for EVM chains\n */\nexport const appendFeesToQuotes = async (\n quotes: QuoteResponse[],\n messenger: BridgeControllerMessenger,\n getLayer1GasFee: typeof TransactionController.prototype.getLayer1GasFee,\n selectedAccount: InternalAccount,\n): Promise<(QuoteResponse & L1GasFees & NonEvmFees)[]> => {\n const quotesWithL1GasFees = await appendL1GasFees(quotes, getLayer1GasFee);\n const quotesWithNonEvmFees = await appendNonEvmFees(\n quotes,\n messenger,\n selectedAccount,\n );\n\n return quotesWithL1GasFees ?? quotesWithNonEvmFees ?? quotes;\n};\n"]}
1
+ {"version":3,"file":"quote-fees.mjs","sourceRoot":"","sources":["../../src/utils/quote-fees.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { TransactionController } from '@metamask/transaction-controller';\nimport { numberToHex } from '@metamask/utils';\n\nimport { isNonEvmChainId, sumHexes } from './bridge';\nimport { formatChainIdToCaip } from './caip-formatters';\nimport { computeFeeRequest } from './snaps';\nimport { CHAIN_IDS } from '../constants/chains';\nimport type {\n QuoteResponse,\n L1GasFees,\n NonEvmFees,\n TxData,\n BridgeControllerMessenger,\n BitcoinTradeData,\n} from '../types';\n\n/**\n * Appends transaction fees for EVM chains to quotes\n *\n * @param quotes - Array of quote responses to append fees to\n * @param getLayer1GasFee - The function to use to get the layer 1 gas fee\n * @returns Array of quotes with fees appended, or undefined if quotes are for non-EVM chains\n */\nconst appendL1GasFees = async (\n quotes: QuoteResponse[],\n getLayer1GasFee: typeof TransactionController.prototype.getLayer1GasFee,\n): Promise<(QuoteResponse & L1GasFees)[] | undefined> => {\n // Indicates whether some of the quotes are not for optimism or base\n const hasInvalidQuotes = quotes.some(({ quote }) => {\n const chainId = formatChainIdToCaip(quote.srcChainId);\n return ![CHAIN_IDS.OPTIMISM, CHAIN_IDS.BASE]\n .map(formatChainIdToCaip)\n .includes(chainId);\n });\n\n // Only append L1 gas fees if all quotes are for either optimism or base\n if (hasInvalidQuotes) {\n return undefined;\n }\n\n const l1GasFeePromises = Promise.allSettled(\n quotes.map(async (quoteResponse) => {\n const { quote, trade, approval } = quoteResponse;\n const chainId = numberToHex(quote.srcChainId);\n\n const getTxParams = (txData: TxData) => ({\n from: txData.from,\n to: txData.to,\n value: txData.value,\n data: txData.data,\n gasLimit: txData.gasLimit?.toString(),\n });\n const approvalL1GasFees = approval\n ? await getLayer1GasFee({\n transactionParams: getTxParams(approval),\n chainId,\n })\n : '0x0';\n const tradeL1GasFees = await getLayer1GasFee({\n transactionParams: getTxParams(trade as TxData),\n chainId,\n });\n\n if (approvalL1GasFees === undefined || tradeL1GasFees === undefined) {\n return undefined;\n }\n\n return {\n ...quoteResponse,\n l1GasFeesInHexWei: sumHexes(approvalL1GasFees, tradeL1GasFees),\n };\n }),\n );\n\n const quotesWithL1GasFees = (await l1GasFeePromises).reduce<\n (QuoteResponse & L1GasFees)[]\n >((acc, result) => {\n if (result.status === 'fulfilled' && result.value) {\n acc.push(result.value);\n } else if (result.status === 'rejected') {\n console.error('Error calculating L1 gas fees for quote', result.reason);\n }\n return acc;\n }, []);\n\n return quotesWithL1GasFees;\n};\n\n/**\n * Appends transaction fees for non-EVM chains to quotes\n *\n * @param quotes - Array of quote responses to append fees to\n * @param messenger - The messaging system to use to call the snap controller\n * @param selectedAccount - The selected account for which the quotes were requested\n * @returns Array of quotes with fees appended, or undefined if quotes are for EVM chains\n */\nconst appendNonEvmFees = async (\n quotes: QuoteResponse[],\n messenger: BridgeControllerMessenger,\n selectedAccount: InternalAccount,\n): Promise<(QuoteResponse & NonEvmFees)[] | undefined> => {\n if (\n quotes.some(({ quote: { srcChainId } }) => !isNonEvmChainId(srcChainId))\n ) {\n return undefined;\n }\n\n const nonEvmFeePromises = Promise.allSettled(\n quotes.map(async (quoteResponse) => {\n const { trade, quote } = quoteResponse;\n\n // Skip fee computation if no snap account or trade data\n if (!selectedAccount?.metadata?.snap?.id || !trade) {\n return quoteResponse;\n }\n\n try {\n const scope = formatChainIdToCaip(quote.srcChainId);\n\n // Normalize trade data to string format expected by snap\n // Solana: trade is already a base64 transaction string\n // Bitcoin: extract unsignedPsbtBase64 from trade object\n const transaction =\n typeof trade === 'string'\n ? trade\n : (trade as BitcoinTradeData).unsignedPsbtBase64;\n\n const response = (await messenger.call(\n 'SnapController:handleRequest',\n computeFeeRequest(\n selectedAccount.metadata.snap?.id,\n transaction,\n selectedAccount.id,\n scope,\n ),\n )) as {\n type: 'base' | 'priority';\n asset: {\n unit: string;\n type: string;\n amount: string;\n fungible: true;\n };\n }[];\n\n // Bitcoin snap returns 'priority' fee, Solana returns 'base' fee\n const fee =\n response?.find((f) => f.type === 'base') ||\n response?.find((f) => f.type === 'priority') ||\n response?.[0];\n const feeInNative = fee?.asset?.amount || '0';\n\n return {\n ...quoteResponse,\n nonEvmFeesInNative: feeInNative,\n };\n } catch (error) {\n // Return quote with undefined fee if snap fails (e.g., insufficient UTXO funds)\n // Client can render special UI or skip the quote card row for quotes with missing fee data\n console.error(\n `Failed to compute non-EVM fees for quote ${quote.requestId}:`,\n error,\n );\n return {\n ...quoteResponse,\n nonEvmFeesInNative: undefined,\n };\n }\n }),\n );\n\n const quotesWithNonEvmFees = (await nonEvmFeePromises).reduce<\n (QuoteResponse & NonEvmFees)[]\n >((acc, result) => {\n if (result.status === 'fulfilled' && result.value) {\n acc.push(result.value);\n } else if (result.status === 'rejected') {\n console.error('Error calculating non-EVM fees for quote', result.reason);\n }\n return acc;\n }, []);\n\n return quotesWithNonEvmFees;\n};\n\n/**\n * Appends transaction fees to quotes\n *\n * @param quotes - Array of quote responses to append fees to\n * @param messenger - The bridge controller to use to call the snap controller\n * @param getLayer1GasFee - The function to use to get the layer 1 gas fee\n * @param selectedAccount - The selected account for which the quotes were requested\n * @returns Array of quotes with fees appended, or undefined if quotes are for EVM chains\n */\nexport const appendFeesToQuotes = async (\n quotes: QuoteResponse[],\n messenger: BridgeControllerMessenger,\n getLayer1GasFee: typeof TransactionController.prototype.getLayer1GasFee,\n selectedAccount: InternalAccount,\n): Promise<(QuoteResponse & L1GasFees & NonEvmFees)[]> => {\n const quotesWithL1GasFees = await appendL1GasFees(quotes, getLayer1GasFee);\n const quotesWithNonEvmFees = await appendNonEvmFees(\n quotes,\n messenger,\n selectedAccount,\n );\n\n return quotesWithL1GasFees ?? quotesWithNonEvmFees ?? quotes;\n};\n"]}
@@ -19,5 +19,5 @@ export declare const BRIDGE_DEFAULT_SLIPPAGE = 0.5;
19
19
 
20
20
  * @returns the default slippage percentage for the chain and token pair
21
21
  */
22
- export declare const getDefaultSlippagePercentage: ({ srcTokenAddress, destTokenAddress, srcChainId, destChainId, }: Partial<Pick<GenericQuoteRequest, 'srcTokenAddress' | 'destTokenAddress' | 'srcChainId' | 'destChainId'>>, srcStablecoins?: string[], destStablecoins?: string[]) => 2 | 0.5 | undefined;
22
+ export declare const getDefaultSlippagePercentage: ({ srcTokenAddress, destTokenAddress, srcChainId, destChainId, }: Partial<Pick<GenericQuoteRequest, 'srcTokenAddress' | 'destTokenAddress' | 'srcChainId' | 'destChainId'>>, srcStablecoins?: string[], destStablecoins?: string[]) => 0.5 | 2 | undefined;
23
23
  //# sourceMappingURL=slippage.d.cts.map
@@ -19,5 +19,5 @@ export declare const BRIDGE_DEFAULT_SLIPPAGE = 0.5;
19
19
 
20
20
  * @returns the default slippage percentage for the chain and token pair
21
21
  */
22
- export declare const getDefaultSlippagePercentage: ({ srcTokenAddress, destTokenAddress, srcChainId, destChainId, }: Partial<Pick<GenericQuoteRequest, 'srcTokenAddress' | 'destTokenAddress' | 'srcChainId' | 'destChainId'>>, srcStablecoins?: string[], destStablecoins?: string[]) => 2 | 0.5 | undefined;
22
+ export declare const getDefaultSlippagePercentage: ({ srcTokenAddress, destTokenAddress, srcChainId, destChainId, }: Partial<Pick<GenericQuoteRequest, 'srcTokenAddress' | 'destTokenAddress' | 'srcChainId' | 'destChainId'>>, srcStablecoins?: string[], destStablecoins?: string[]) => 0.5 | 2 | undefined;
23
23
  //# sourceMappingURL=slippage.d.mts.map