{"version":3,"file":"quote-fees.mjs","sourceRoot":"","sources":["../../src/utils/quote-fees.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAE9C,OAAO,EAAE,SAAS,EAAE,gCAA4B;AAQhD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,qBAAiB;AACrD,OAAO,EAAE,mBAAmB,EAAE,8BAA0B;AACxD,OAAO,EAAE,iBAAiB,EAAE,oBAAgB;AAC5C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,0BAAsB;AAE9D;;;;;;GAMG;AACH,MAAM,eAAe,GAAG,KAAK,EAC3B,MAAyC,EACzC,eAAuE,EACD,EAAE;IACxE,oEAAoE;IACpE,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtD,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC;aACzC,GAAG,CAAC,mBAAmB,CAAC;aACxB,QAAQ,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,wEAAwE;IACxE,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,CACzC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;QACjC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;QACjD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAE9C,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;YACvC,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE;SACtC,CAAC,CAAC;QACH,MAAM,iBAAiB,GAAG,QAAQ;YAChC,CAAC,CAAC,MAAM,eAAe,CAAC;gBACpB,iBAAiB,EAAE,WAAW,CAAC,QAAQ,CAAC;gBACxC,OAAO;aACR,CAAC;YACJ,CAAC,CAAC,KAAK,CAAC;QACV,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC;YAC3C,iBAAiB,EAAE,WAAW,CAAC,KAAe,CAAC;YAC/C,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,iBAAiB,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACpE,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO;YACL,GAAG,aAAa;YAChB,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,cAAc,CAAC;SAC/D,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,mBAAmB,GAAG,CAAC,MAAM,gBAAgB,CAAC,CAAC,MAAM,CAEzD,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;QAChB,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAClD,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACxC,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,mBAAmB,CAAC;AAC7B,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,gBAAgB,GAAG,KAAK,EAC5B,MAAyB,EACzB,SAAoC,EACpC,eAAiC,EACsB,EAAE;IACzD,IACE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,EACxE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAC1C,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;QACjC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,aAAa,CAAC;QAEvC,wDAAwD;QACxD,IAAI,CAAC,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YACnD,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAEpD,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAE5C,4FAA4F;YAC5F,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC;gBAChC,CAAC,CAAC;oBACE,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI;oBACzC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS;iBACpC;gBACH,CAAC,CAAC,SAAS,CAAC;YAEd,MAAM,QAAQ,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CACpC,8BAA8B,EAC9B,iBAAiB,CACf,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EACnC,WAAW,EACX,eAAe,EAAE,EAAE,EACnB,KAAK,EACL,OAAO,CACR,CACF,CAQE,CAAC;YAEJ,iEAAiE;YACjE,MAAM,GAAG,GACP,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;gBACxC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC;gBAC5C,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;YAChB,MAAM,WAAW,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,CAAC;YAE9C,OAAO;gBACL,GAAG,aAAa;gBAChB,kBAAkB,EAAE,WAAW;aAChC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gFAAgF;YAChF,2FAA2F;YAC3F,OAAO,CAAC,KAAK,CACX,4CAA4C,KAAK,CAAC,SAAS,GAAG,EAC9D,KAAK,CACN,CAAC;YACF,OAAO;gBACL,GAAG,aAAa;gBAChB,kBAAkB,EAAE,SAAS;aAC9B,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,oBAAoB,GAAG,CAAC,MAAM,iBAAiB,CAAC,CAAC,MAAM,CAE3D,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;QAChB,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAClD,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACrC,MAAyB,EACzB,SAAoC,EACpC,eAAuE,EACvE,eAAiC,EACsB,EAAE;IACzD,6FAA6F;IAC7F,MAAM,mBAAmB,GAAG,MAAM,eAAe,CAC/C,MAA2C,EAC3C,eAAe,CAChB,CAAC;IACF,MAAM,oBAAoB,GAAG,MAAM,gBAAgB,CACjD,MAAM,EACN,SAAS,EACT,eAAe,CAChB,CAAC;IAEF,OAAO,mBAAmB,IAAI,oBAAoB,IAAI,MAAM,CAAC;AAC/D,CAAC,CAAC","sourcesContent":["import type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { TransactionController } from '@metamask/transaction-controller';\nimport { numberToHex } from '@metamask/utils';\n\nimport { CHAIN_IDS } from '../constants/chains';\nimport type {\n  QuoteResponseV1,\n  L1GasFees,\n  NonEvmFees,\n  TxData,\n  BridgeControllerMessenger,\n} from '../types';\nimport { isNonEvmChainId, sumHexes } from './bridge';\nimport { formatChainIdToCaip } from './caip-formatters';\nimport { computeFeeRequest } from './snaps';\nimport { extractTradeData, isTronTrade } from './trade-utils';\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: QuoteResponseV1<TxData, TxData>[],\n  getLayer1GasFee: typeof TransactionController.prototype.getLayer1GasFee,\n): Promise<(QuoteResponseV1<TxData, TxData> & 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    (QuoteResponseV1<TxData, TxData> & 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: QuoteResponseV1[],\n  messenger: BridgeControllerMessenger,\n  selectedAccount?: InternalAccount,\n): Promise<(QuoteResponseV1 & 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        const transaction = extractTradeData(trade);\n\n        // Tron trades need the visible flag and contract type to be included in the request options\n        const options = isTronTrade(trade)\n          ? {\n              visible: trade.visible,\n              type: trade.raw_data?.contract?.[0]?.type,\n              feeLimit: trade.raw_data?.fee_limit,\n            }\n          : undefined;\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            options,\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    (QuoteResponseV1 & NonEvmFees)[]\n  >((acc, result) => {\n    if (result.status === 'fulfilled' && result.value) {\n      acc.push(result.value);\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: QuoteResponseV1[],\n  messenger: BridgeControllerMessenger,\n  getLayer1GasFee: typeof TransactionController.prototype.getLayer1GasFee,\n  selectedAccount?: InternalAccount,\n): Promise<(QuoteResponseV1 & L1GasFees & NonEvmFees)[]> => {\n  // Safe to cast: appendL1GasFees checks if all quotes are EVM and returns undefined otherwise\n  const quotesWithL1GasFees = await appendL1GasFees(\n    quotes as QuoteResponseV1<TxData, TxData>[],\n    getLayer1GasFee,\n  );\n  const quotesWithNonEvmFees = await appendNonEvmFees(\n    quotes,\n    messenger,\n    selectedAccount,\n  );\n\n  return quotesWithL1GasFees ?? quotesWithNonEvmFees ?? quotes;\n};\n"]}