@metamask-previews/transaction-pay-controller 27.1.0-preview-6ed11f88f → 27.1.0-preview-ec24abb79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
+ - Use the native Transak buy quote's fee for the MM Pay fiat estimate when Transak Native is the resolved provider, falling back to the aggregator quote's fee when native is unavailable or the lookup fails ([#9317](https://github.com/MetaMask/core/pull/9317))
12
13
  - Keep direct Monad mUSD on-ramp fees visible while treating them as included in the entered fiat total. ([#9317](https://github.com/MetaMask/core/pull/9317))
13
14
 
14
15
  ## [27.1.0]
@@ -39,6 +39,17 @@ async function getDirectMusdFiatQuote({ amountFiat, fiatPaymentMethod, messenger
39
39
  messenger,
40
40
  walletAddress: moneyAccountAddress,
41
41
  });
42
+ // When Transak Native is the resolved provider, prefer its own quote's fee
43
+ // so the estimate matches what Transak Native will charge. Direct mUSD
44
+ // checkout is fee-inclusive, so request the native quote in that mode.
45
+ const nativeRampsFee = await (0, utils_js_1.getNativeTransakRampsFee)({
46
+ adjustedAmount,
47
+ fiatAsset: constants_js_2.MUSD_MONAD_FIAT_ASSET,
48
+ fiatPaymentMethod,
49
+ fiatQuote,
50
+ isFeeExcludedFromFiat: false,
51
+ messenger,
52
+ });
42
53
  messenger.call('TransactionPayController:updateFiatPayment', {
43
54
  callback: (fiatPayment) => {
44
55
  fiatPayment.rampsQuote = fiatQuote;
@@ -56,6 +67,7 @@ async function getDirectMusdFiatQuote({ amountFiat, fiatPaymentMethod, messenger
56
67
  fiatQuote,
57
68
  messenger,
58
69
  moneyAccountAddress,
70
+ nativeRampsFee,
59
71
  requiredToken,
60
72
  });
61
73
  }
@@ -110,7 +122,7 @@ async function submitDirectMusdAfterFiatCompletion({ order, request, }) {
110
122
  }
111
123
  }
112
124
  exports.submitDirectMusdAfterFiatCompletion = submitDirectMusdAfterFiatCompletion;
113
- function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAccountAddress, requiredToken, }) {
125
+ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAccountAddress, nativeRampsFee, requiredToken, }) {
114
126
  const tokenInfo = (0, token_js_1.getTokenInfo)(messenger, constants_js_2.MUSD_MONAD_FIAT_ASSET.address, constants_js_2.MUSD_MONAD_FIAT_ASSET.chainId);
115
127
  if (!tokenInfo) {
116
128
  throw new Error('Unable to resolve mUSD token info for direct fiat quote');
@@ -119,8 +131,14 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
119
131
  cryptoAmount: fiatQuote.quote.amountOut,
120
132
  decimals: tokenInfo.decimals,
121
133
  });
122
- const rampsProviderFee = getSafeFee(fiatQuote.quote.providerFee).toString(10);
123
- const rampsNetworkFee = getSafeFee(fiatQuote.quote.networkFee).toString(10);
134
+ // Transak Native returns a single total fee, so the aggregator's separate
135
+ // provider/network split collapses: the whole native fee sits in the provider
136
+ // bucket and the source-network fee is zero. The `providerFiat` total stays
137
+ // correct either way.
138
+ const rampsProviderFee = (nativeRampsFee ?? getSafeFee(fiatQuote.quote.providerFee)).toString(10);
139
+ const rampsNetworkFee = nativeRampsFee
140
+ ? '0'
141
+ : getSafeFee(fiatQuote.quote.networkFee).toString(10);
124
142
  const rampsTotalFee = new bignumber_js_1.BigNumber(rampsProviderFee)
125
143
  .plus(rampsNetworkFee)
126
144
  .toString(10);
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-direct-musd.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Quote as RampsQuote,\n RampsOrder,\n} from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { TransactionPayStrategy } from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyExecuteRequest,\n PayStrategyGetQuotesRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { prefixError } from '../../utils/error-prefix.js';\nimport { getFiatVaultDisabled } from '../../utils/feature-flags.js';\nimport { submitMoneyAccountVaultDeposit } from '../../utils/ma-vault-deposit.js';\nimport { buildCaipAssetType, getTokenInfo } from '../../utils/token.js';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants.js';\nimport type { FiatQuote } from './types.js';\nimport {\n getRampsQuote,\n getRawSourceAmountFromOrderCryptoAmount,\n resolveSourceAmountRaw,\n validateOrderAsset,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-direct-musd');\nconst DIRECT_MUSD_ERROR_PREFIX = 'Direct mUSD: ';\n\n/**\n * Returns a direct mUSD fiat quote to the Money Account.\n *\n * @param options - Direct quote options.\n * @param options.amountFiat - Fiat amount entered by the user.\n * @param options.fiatPaymentMethod - Selected fiat payment method.\n * @param options.messenger - Controller messenger.\n * @param options.moneyAccountAddress - Money Account receiving the on-ramped mUSD.\n * @param options.requiredToken - Required token from the original Money Account transaction.\n * @param options.transactionId - Transaction ID for state updates and logs.\n * @returns Direct mUSD Fiat quote, or undefined when unavailable.\n */\nexport async function getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod,\n messenger,\n moneyAccountAddress,\n requiredToken,\n transactionId,\n}: {\n amountFiat: string;\n fiatPaymentMethod: string;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n requiredToken: TransactionPayRequiredToken;\n transactionId: string;\n}): Promise<TransactionPayQuote<FiatQuote> | undefined> {\n try {\n const adjustedAmount = Number(amountFiat);\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount for direct mUSD quote');\n }\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n errorMessage: 'No matching ramps quote found for direct mUSD provider',\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n fiatPaymentMethod,\n messenger,\n walletAddress: moneyAccountAddress,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n MUSD_MONAD_FIAT_ASSET.chainId,\n MUSD_MONAD_FIAT_ASSET.address,\n );\n },\n transactionId,\n });\n\n log('Direct mUSD fiat quote flow', {\n amountFiat,\n moneyAccountAddress,\n transactionId,\n });\n\n return combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n requiredToken,\n });\n } catch (error) {\n log('Direct mUSD fiat quote failed', { error, transactionId });\n return undefined;\n }\n}\n\n/**\n * Detects a direct mUSD Money Account quote from its stored request marker.\n *\n * @param quote - Quote to inspect.\n * @returns True when the quote originated from the direct mUSD fiat path.\n */\nexport function isDirectMusdMoneyAccountQuote(\n quote: Pick<TransactionPayQuote<unknown>, 'request'> | undefined,\n): boolean {\n return quote?.request.isDirectMusdMoneyAccount === true;\n}\n\n/**\n * Submits the direct mUSD post-Ramp path after fiat settlement.\n *\n * @param options - Submit options.\n * @param options.order - Completed fiat order.\n * @param options.request - Strategy execute request.\n * @returns Hash of the submitted direct mUSD transaction, if available.\n */\nexport async function submitDirectMusdAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, transaction } = request;\n\n try {\n validateOrderAsset({\n expectedAsset: MUSD_MONAD_FIAT_ASSET,\n orderCrypto: order.cryptoCurrency,\n transactionId: transaction.id,\n });\n\n const { amountRaw: sourceAmountRaw, fromBlock } =\n await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n walletAddress: transaction.txParams.from as Hex,\n });\n\n return await submitMoneyAccountVaultDeposit({\n fromBlock,\n messenger,\n sourceAmountRaw,\n transaction,\n vaultDisabled: getFiatVaultDisabled(messenger),\n });\n } catch (error) {\n throw prefixError(error, DIRECT_MUSD_ERROR_PREFIX);\n }\n}\n\nfunction combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n requiredToken,\n}: {\n amountFiat: string;\n fiatQuote: RampsQuote;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n requiredToken: TransactionPayRequiredToken;\n}): TransactionPayQuote<FiatQuote> {\n const tokenInfo = getTokenInfo(\n messenger,\n MUSD_MONAD_FIAT_ASSET.address,\n MUSD_MONAD_FIAT_ASSET.chainId,\n );\n\n if (!tokenInfo) {\n throw new Error('Unable to resolve mUSD token info for direct fiat quote');\n }\n\n const sourceAmountRaw = getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount: fiatQuote.quote.amountOut,\n decimals: tokenInfo.decimals,\n });\n const rampsProviderFee = getSafeFee(fiatQuote.quote.providerFee).toString(10);\n const rampsNetworkFee = getSafeFee(fiatQuote.quote.networkFee).toString(10);\n const rampsTotalFee = new BigNumber(rampsProviderFee)\n .plus(rampsNetworkFee)\n .toString(10);\n const targetAmountFiat = getDirectMusdTargetAmountFiat(fiatQuote);\n const sourceAmountHuman = new BigNumber(sourceAmountRaw)\n .shiftedBy(-tokenInfo.decimals)\n .toString(10);\n\n return {\n areFeesIncludedInSourceAmount: true,\n dust: { fiat: '0', usd: '0' },\n estimatedDuration: 0,\n fees: {\n metaMask: { fiat: '0', usd: '0' },\n provider: { fiat: rampsProviderFee, usd: rampsProviderFee },\n providerFiat: { fiat: rampsTotalFee, usd: rampsTotalFee },\n sourceNetwork: {\n estimate: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n max: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n },\n targetNetwork: { fiat: '0', usd: '0' },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: undefined,\n },\n request: {\n from: moneyAccountAddress,\n isDirectMusdMoneyAccount: true,\n recipient: moneyAccountAddress,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: MUSD_MONAD_FIAT_ASSET.chainId,\n sourceTokenAddress: MUSD_MONAD_FIAT_ASSET.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: sourceAmountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n },\n sourceAmount: {\n fiat: amountFiat,\n human: sourceAmountHuman,\n raw: sourceAmountRaw,\n usd: amountFiat,\n },\n strategy: TransactionPayStrategy.Fiat,\n targetAmount: { fiat: targetAmountFiat, usd: targetAmountFiat },\n };\n}\n\nfunction getDirectMusdTargetAmountFiat(fiatQuote: RampsQuote): string {\n const amountOutInFiat = new BigNumber(fiatQuote.quote.amountOutInFiat ?? NaN);\n if (amountOutInFiat.isFinite() && amountOutInFiat.isGreaterThanOrEqualTo(0)) {\n return amountOutInFiat.toString(10);\n }\n\n return new BigNumber(fiatQuote.quote.amountOut).toString(10);\n}\n\nfunction getSafeFee(value: BigNumber.Value | undefined): BigNumber {\n const fee = new BigNumber(value ?? 0);\n return fee.isFinite() && fee.isGreaterThanOrEqualTo(0)\n ? fee\n : new BigNumber(0);\n}\n"]}
1
+ {"version":3,"file":"fiat-direct-musd.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Quote as RampsQuote,\n RampsOrder,\n} from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { TransactionPayStrategy } from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyExecuteRequest,\n PayStrategyGetQuotesRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { prefixError } from '../../utils/error-prefix.js';\nimport { getFiatVaultDisabled } from '../../utils/feature-flags.js';\nimport { submitMoneyAccountVaultDeposit } from '../../utils/ma-vault-deposit.js';\nimport { buildCaipAssetType, getTokenInfo } from '../../utils/token.js';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants.js';\nimport type { FiatQuote } from './types.js';\nimport {\n getNativeTransakRampsFee,\n getRampsQuote,\n getRawSourceAmountFromOrderCryptoAmount,\n resolveSourceAmountRaw,\n validateOrderAsset,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-direct-musd');\nconst DIRECT_MUSD_ERROR_PREFIX = 'Direct mUSD: ';\n\n/**\n * Returns a direct mUSD fiat quote to the Money Account.\n *\n * @param options - Direct quote options.\n * @param options.amountFiat - Fiat amount entered by the user.\n * @param options.fiatPaymentMethod - Selected fiat payment method.\n * @param options.messenger - Controller messenger.\n * @param options.moneyAccountAddress - Money Account receiving the on-ramped mUSD.\n * @param options.requiredToken - Required token from the original Money Account transaction.\n * @param options.transactionId - Transaction ID for state updates and logs.\n * @returns Direct mUSD Fiat quote, or undefined when unavailable.\n */\nexport async function getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod,\n messenger,\n moneyAccountAddress,\n requiredToken,\n transactionId,\n}: {\n amountFiat: string;\n fiatPaymentMethod: string;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n requiredToken: TransactionPayRequiredToken;\n transactionId: string;\n}): Promise<TransactionPayQuote<FiatQuote> | undefined> {\n try {\n const adjustedAmount = Number(amountFiat);\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount for direct mUSD quote');\n }\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n errorMessage: 'No matching ramps quote found for direct mUSD provider',\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n fiatPaymentMethod,\n messenger,\n walletAddress: moneyAccountAddress,\n });\n\n // When Transak Native is the resolved provider, prefer its own quote's fee\n // so the estimate matches what Transak Native will charge. Direct mUSD\n // checkout is fee-inclusive, so request the native quote in that mode.\n const nativeRampsFee = await getNativeTransakRampsFee({\n adjustedAmount,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n fiatPaymentMethod,\n fiatQuote,\n isFeeExcludedFromFiat: false,\n messenger,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n MUSD_MONAD_FIAT_ASSET.chainId,\n MUSD_MONAD_FIAT_ASSET.address,\n );\n },\n transactionId,\n });\n\n log('Direct mUSD fiat quote flow', {\n amountFiat,\n moneyAccountAddress,\n transactionId,\n });\n\n return combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n nativeRampsFee,\n requiredToken,\n });\n } catch (error) {\n log('Direct mUSD fiat quote failed', { error, transactionId });\n return undefined;\n }\n}\n\n/**\n * Detects a direct mUSD Money Account quote from its stored request marker.\n *\n * @param quote - Quote to inspect.\n * @returns True when the quote originated from the direct mUSD fiat path.\n */\nexport function isDirectMusdMoneyAccountQuote(\n quote: Pick<TransactionPayQuote<unknown>, 'request'> | undefined,\n): boolean {\n return quote?.request.isDirectMusdMoneyAccount === true;\n}\n\n/**\n * Submits the direct mUSD post-Ramp path after fiat settlement.\n *\n * @param options - Submit options.\n * @param options.order - Completed fiat order.\n * @param options.request - Strategy execute request.\n * @returns Hash of the submitted direct mUSD transaction, if available.\n */\nexport async function submitDirectMusdAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, transaction } = request;\n\n try {\n validateOrderAsset({\n expectedAsset: MUSD_MONAD_FIAT_ASSET,\n orderCrypto: order.cryptoCurrency,\n transactionId: transaction.id,\n });\n\n const { amountRaw: sourceAmountRaw, fromBlock } =\n await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n walletAddress: transaction.txParams.from as Hex,\n });\n\n return await submitMoneyAccountVaultDeposit({\n fromBlock,\n messenger,\n sourceAmountRaw,\n transaction,\n vaultDisabled: getFiatVaultDisabled(messenger),\n });\n } catch (error) {\n throw prefixError(error, DIRECT_MUSD_ERROR_PREFIX);\n }\n}\n\nfunction combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n nativeRampsFee,\n requiredToken,\n}: {\n amountFiat: string;\n fiatQuote: RampsQuote;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n nativeRampsFee: BigNumber | null;\n requiredToken: TransactionPayRequiredToken;\n}): TransactionPayQuote<FiatQuote> {\n const tokenInfo = getTokenInfo(\n messenger,\n MUSD_MONAD_FIAT_ASSET.address,\n MUSD_MONAD_FIAT_ASSET.chainId,\n );\n\n if (!tokenInfo) {\n throw new Error('Unable to resolve mUSD token info for direct fiat quote');\n }\n\n const sourceAmountRaw = getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount: fiatQuote.quote.amountOut,\n decimals: tokenInfo.decimals,\n });\n // Transak Native returns a single total fee, so the aggregator's separate\n // provider/network split collapses: the whole native fee sits in the provider\n // bucket and the source-network fee is zero. The `providerFiat` total stays\n // correct either way.\n const rampsProviderFee = (\n nativeRampsFee ?? getSafeFee(fiatQuote.quote.providerFee)\n ).toString(10);\n const rampsNetworkFee = nativeRampsFee\n ? '0'\n : getSafeFee(fiatQuote.quote.networkFee).toString(10);\n const rampsTotalFee = new BigNumber(rampsProviderFee)\n .plus(rampsNetworkFee)\n .toString(10);\n const targetAmountFiat = getDirectMusdTargetAmountFiat(fiatQuote);\n const sourceAmountHuman = new BigNumber(sourceAmountRaw)\n .shiftedBy(-tokenInfo.decimals)\n .toString(10);\n\n return {\n areFeesIncludedInSourceAmount: true,\n dust: { fiat: '0', usd: '0' },\n estimatedDuration: 0,\n fees: {\n metaMask: { fiat: '0', usd: '0' },\n provider: { fiat: rampsProviderFee, usd: rampsProviderFee },\n providerFiat: { fiat: rampsTotalFee, usd: rampsTotalFee },\n sourceNetwork: {\n estimate: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n max: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n },\n targetNetwork: { fiat: '0', usd: '0' },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: undefined,\n },\n request: {\n from: moneyAccountAddress,\n isDirectMusdMoneyAccount: true,\n recipient: moneyAccountAddress,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: MUSD_MONAD_FIAT_ASSET.chainId,\n sourceTokenAddress: MUSD_MONAD_FIAT_ASSET.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: sourceAmountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n },\n sourceAmount: {\n fiat: amountFiat,\n human: sourceAmountHuman,\n raw: sourceAmountRaw,\n usd: amountFiat,\n },\n strategy: TransactionPayStrategy.Fiat,\n targetAmount: { fiat: targetAmountFiat, usd: targetAmountFiat },\n };\n}\n\nfunction getDirectMusdTargetAmountFiat(fiatQuote: RampsQuote): string {\n const amountOutInFiat = new BigNumber(fiatQuote.quote.amountOutInFiat ?? NaN);\n if (amountOutInFiat.isFinite() && amountOutInFiat.isGreaterThanOrEqualTo(0)) {\n return amountOutInFiat.toString(10);\n }\n\n return new BigNumber(fiatQuote.quote.amountOut).toString(10);\n}\n\nfunction getSafeFee(value: BigNumber.Value | undefined): BigNumber {\n const fee = new BigNumber(value ?? 0);\n return fee.isFinite() && fee.isGreaterThanOrEqualTo(0)\n ? fee\n : new BigNumber(0);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-direct-musd.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EACX,mCAAmC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAM3C,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE3B,2BAA2B,EAC3B,mBAAmB,EACpB,wBAAuB;AAMxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAW5C;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,aAAa,GACd,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,2BAA2B,CAAC,WAAW,CAAC,CAAC;IACpD,mBAAmB,EAAE,GAAG,CAAC;IACzB,aAAa,EAAE,2BAA2B,CAAC;IAC3C,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CA6CtD;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,GAC/D,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAsB,mCAAmC,CAAC,EACxD,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;CAC/C,GAAG,OAAO,CAAC;IAAE,eAAe,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CA4BrC"}
1
+ {"version":3,"file":"fiat-direct-musd.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EACX,mCAAmC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAM3C,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE3B,2BAA2B,EAC3B,mBAAmB,EACpB,wBAAuB;AAMxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAY5C;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,aAAa,GACd,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,2BAA2B,CAAC,WAAW,CAAC,CAAC;IACpD,mBAAmB,EAAE,GAAG,CAAC;IACzB,aAAa,EAAE,2BAA2B,CAAC;IAC3C,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CA0DtD;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,GAC/D,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAsB,mCAAmC,CAAC,EACxD,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;CAC/C,GAAG,OAAO,CAAC;IAAE,eAAe,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CA4BrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-direct-musd.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EACX,mCAAmC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAM3C,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE3B,2BAA2B,EAC3B,mBAAmB,EACpB,wBAAuB;AAMxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAW5C;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,aAAa,GACd,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,2BAA2B,CAAC,WAAW,CAAC,CAAC;IACpD,mBAAmB,EAAE,GAAG,CAAC;IACzB,aAAa,EAAE,2BAA2B,CAAC;IAC3C,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CA6CtD;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,GAC/D,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAsB,mCAAmC,CAAC,EACxD,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;CAC/C,GAAG,OAAO,CAAC;IAAE,eAAe,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CA4BrC"}
1
+ {"version":3,"file":"fiat-direct-musd.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EACX,mCAAmC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAM3C,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE3B,2BAA2B,EAC3B,mBAAmB,EACpB,wBAAuB;AAMxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAY5C;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,aAAa,GACd,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,2BAA2B,CAAC,WAAW,CAAC,CAAC;IACpD,mBAAmB,EAAE,GAAG,CAAC;IACzB,aAAa,EAAE,2BAA2B,CAAC;IAC3C,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CA0DtD;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,GAC/D,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAsB,mCAAmC,CAAC,EACxD,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;CAC/C,GAAG,OAAO,CAAC;IAAE,eAAe,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CA4BrC"}
@@ -7,7 +7,7 @@ import { getFiatVaultDisabled } from "../../utils/feature-flags.mjs";
7
7
  import { submitMoneyAccountVaultDeposit } from "../../utils/ma-vault-deposit.mjs";
8
8
  import { buildCaipAssetType, getTokenInfo } from "../../utils/token.mjs";
9
9
  import { MUSD_MONAD_FIAT_ASSET } from "./constants.mjs";
10
- import { getRampsQuote, getRawSourceAmountFromOrderCryptoAmount, resolveSourceAmountRaw, validateOrderAsset } from "./utils.mjs";
10
+ import { getNativeTransakRampsFee, getRampsQuote, getRawSourceAmountFromOrderCryptoAmount, resolveSourceAmountRaw, validateOrderAsset } from "./utils.mjs";
11
11
  const log = createModuleLogger(projectLogger, 'fiat-direct-musd');
12
12
  const DIRECT_MUSD_ERROR_PREFIX = 'Direct mUSD: ';
13
13
  /**
@@ -36,6 +36,17 @@ export async function getDirectMusdFiatQuote({ amountFiat, fiatPaymentMethod, me
36
36
  messenger,
37
37
  walletAddress: moneyAccountAddress,
38
38
  });
39
+ // When Transak Native is the resolved provider, prefer its own quote's fee
40
+ // so the estimate matches what Transak Native will charge. Direct mUSD
41
+ // checkout is fee-inclusive, so request the native quote in that mode.
42
+ const nativeRampsFee = await getNativeTransakRampsFee({
43
+ adjustedAmount,
44
+ fiatAsset: MUSD_MONAD_FIAT_ASSET,
45
+ fiatPaymentMethod,
46
+ fiatQuote,
47
+ isFeeExcludedFromFiat: false,
48
+ messenger,
49
+ });
39
50
  messenger.call('TransactionPayController:updateFiatPayment', {
40
51
  callback: (fiatPayment) => {
41
52
  fiatPayment.rampsQuote = fiatQuote;
@@ -53,6 +64,7 @@ export async function getDirectMusdFiatQuote({ amountFiat, fiatPaymentMethod, me
53
64
  fiatQuote,
54
65
  messenger,
55
66
  moneyAccountAddress,
67
+ nativeRampsFee,
56
68
  requiredToken,
57
69
  });
58
70
  }
@@ -104,7 +116,7 @@ export async function submitDirectMusdAfterFiatCompletion({ order, request, }) {
104
116
  throw prefixError(error, DIRECT_MUSD_ERROR_PREFIX);
105
117
  }
106
118
  }
107
- function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAccountAddress, requiredToken, }) {
119
+ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAccountAddress, nativeRampsFee, requiredToken, }) {
108
120
  const tokenInfo = getTokenInfo(messenger, MUSD_MONAD_FIAT_ASSET.address, MUSD_MONAD_FIAT_ASSET.chainId);
109
121
  if (!tokenInfo) {
110
122
  throw new Error('Unable to resolve mUSD token info for direct fiat quote');
@@ -113,8 +125,14 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
113
125
  cryptoAmount: fiatQuote.quote.amountOut,
114
126
  decimals: tokenInfo.decimals,
115
127
  });
116
- const rampsProviderFee = getSafeFee(fiatQuote.quote.providerFee).toString(10);
117
- const rampsNetworkFee = getSafeFee(fiatQuote.quote.networkFee).toString(10);
128
+ // Transak Native returns a single total fee, so the aggregator's separate
129
+ // provider/network split collapses: the whole native fee sits in the provider
130
+ // bucket and the source-network fee is zero. The `providerFiat` total stays
131
+ // correct either way.
132
+ const rampsProviderFee = (nativeRampsFee ?? getSafeFee(fiatQuote.quote.providerFee)).toString(10);
133
+ const rampsNetworkFee = nativeRampsFee
134
+ ? '0'
135
+ : getSafeFee(fiatQuote.quote.networkFee).toString(10);
118
136
  const rampsTotalFee = new BigNumber(rampsProviderFee)
119
137
  .plus(rampsNetworkFee)
120
138
  .toString(10);
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-direct-musd.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Quote as RampsQuote,\n RampsOrder,\n} from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { TransactionPayStrategy } from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyExecuteRequest,\n PayStrategyGetQuotesRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { prefixError } from '../../utils/error-prefix.js';\nimport { getFiatVaultDisabled } from '../../utils/feature-flags.js';\nimport { submitMoneyAccountVaultDeposit } from '../../utils/ma-vault-deposit.js';\nimport { buildCaipAssetType, getTokenInfo } from '../../utils/token.js';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants.js';\nimport type { FiatQuote } from './types.js';\nimport {\n getRampsQuote,\n getRawSourceAmountFromOrderCryptoAmount,\n resolveSourceAmountRaw,\n validateOrderAsset,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-direct-musd');\nconst DIRECT_MUSD_ERROR_PREFIX = 'Direct mUSD: ';\n\n/**\n * Returns a direct mUSD fiat quote to the Money Account.\n *\n * @param options - Direct quote options.\n * @param options.amountFiat - Fiat amount entered by the user.\n * @param options.fiatPaymentMethod - Selected fiat payment method.\n * @param options.messenger - Controller messenger.\n * @param options.moneyAccountAddress - Money Account receiving the on-ramped mUSD.\n * @param options.requiredToken - Required token from the original Money Account transaction.\n * @param options.transactionId - Transaction ID for state updates and logs.\n * @returns Direct mUSD Fiat quote, or undefined when unavailable.\n */\nexport async function getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod,\n messenger,\n moneyAccountAddress,\n requiredToken,\n transactionId,\n}: {\n amountFiat: string;\n fiatPaymentMethod: string;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n requiredToken: TransactionPayRequiredToken;\n transactionId: string;\n}): Promise<TransactionPayQuote<FiatQuote> | undefined> {\n try {\n const adjustedAmount = Number(amountFiat);\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount for direct mUSD quote');\n }\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n errorMessage: 'No matching ramps quote found for direct mUSD provider',\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n fiatPaymentMethod,\n messenger,\n walletAddress: moneyAccountAddress,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n MUSD_MONAD_FIAT_ASSET.chainId,\n MUSD_MONAD_FIAT_ASSET.address,\n );\n },\n transactionId,\n });\n\n log('Direct mUSD fiat quote flow', {\n amountFiat,\n moneyAccountAddress,\n transactionId,\n });\n\n return combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n requiredToken,\n });\n } catch (error) {\n log('Direct mUSD fiat quote failed', { error, transactionId });\n return undefined;\n }\n}\n\n/**\n * Detects a direct mUSD Money Account quote from its stored request marker.\n *\n * @param quote - Quote to inspect.\n * @returns True when the quote originated from the direct mUSD fiat path.\n */\nexport function isDirectMusdMoneyAccountQuote(\n quote: Pick<TransactionPayQuote<unknown>, 'request'> | undefined,\n): boolean {\n return quote?.request.isDirectMusdMoneyAccount === true;\n}\n\n/**\n * Submits the direct mUSD post-Ramp path after fiat settlement.\n *\n * @param options - Submit options.\n * @param options.order - Completed fiat order.\n * @param options.request - Strategy execute request.\n * @returns Hash of the submitted direct mUSD transaction, if available.\n */\nexport async function submitDirectMusdAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, transaction } = request;\n\n try {\n validateOrderAsset({\n expectedAsset: MUSD_MONAD_FIAT_ASSET,\n orderCrypto: order.cryptoCurrency,\n transactionId: transaction.id,\n });\n\n const { amountRaw: sourceAmountRaw, fromBlock } =\n await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n walletAddress: transaction.txParams.from as Hex,\n });\n\n return await submitMoneyAccountVaultDeposit({\n fromBlock,\n messenger,\n sourceAmountRaw,\n transaction,\n vaultDisabled: getFiatVaultDisabled(messenger),\n });\n } catch (error) {\n throw prefixError(error, DIRECT_MUSD_ERROR_PREFIX);\n }\n}\n\nfunction combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n requiredToken,\n}: {\n amountFiat: string;\n fiatQuote: RampsQuote;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n requiredToken: TransactionPayRequiredToken;\n}): TransactionPayQuote<FiatQuote> {\n const tokenInfo = getTokenInfo(\n messenger,\n MUSD_MONAD_FIAT_ASSET.address,\n MUSD_MONAD_FIAT_ASSET.chainId,\n );\n\n if (!tokenInfo) {\n throw new Error('Unable to resolve mUSD token info for direct fiat quote');\n }\n\n const sourceAmountRaw = getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount: fiatQuote.quote.amountOut,\n decimals: tokenInfo.decimals,\n });\n const rampsProviderFee = getSafeFee(fiatQuote.quote.providerFee).toString(10);\n const rampsNetworkFee = getSafeFee(fiatQuote.quote.networkFee).toString(10);\n const rampsTotalFee = new BigNumber(rampsProviderFee)\n .plus(rampsNetworkFee)\n .toString(10);\n const targetAmountFiat = getDirectMusdTargetAmountFiat(fiatQuote);\n const sourceAmountHuman = new BigNumber(sourceAmountRaw)\n .shiftedBy(-tokenInfo.decimals)\n .toString(10);\n\n return {\n areFeesIncludedInSourceAmount: true,\n dust: { fiat: '0', usd: '0' },\n estimatedDuration: 0,\n fees: {\n metaMask: { fiat: '0', usd: '0' },\n provider: { fiat: rampsProviderFee, usd: rampsProviderFee },\n providerFiat: { fiat: rampsTotalFee, usd: rampsTotalFee },\n sourceNetwork: {\n estimate: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n max: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n },\n targetNetwork: { fiat: '0', usd: '0' },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: undefined,\n },\n request: {\n from: moneyAccountAddress,\n isDirectMusdMoneyAccount: true,\n recipient: moneyAccountAddress,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: MUSD_MONAD_FIAT_ASSET.chainId,\n sourceTokenAddress: MUSD_MONAD_FIAT_ASSET.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: sourceAmountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n },\n sourceAmount: {\n fiat: amountFiat,\n human: sourceAmountHuman,\n raw: sourceAmountRaw,\n usd: amountFiat,\n },\n strategy: TransactionPayStrategy.Fiat,\n targetAmount: { fiat: targetAmountFiat, usd: targetAmountFiat },\n };\n}\n\nfunction getDirectMusdTargetAmountFiat(fiatQuote: RampsQuote): string {\n const amountOutInFiat = new BigNumber(fiatQuote.quote.amountOutInFiat ?? NaN);\n if (amountOutInFiat.isFinite() && amountOutInFiat.isGreaterThanOrEqualTo(0)) {\n return amountOutInFiat.toString(10);\n }\n\n return new BigNumber(fiatQuote.quote.amountOut).toString(10);\n}\n\nfunction getSafeFee(value: BigNumber.Value | undefined): BigNumber {\n const fee = new BigNumber(value ?? 0);\n return fee.isFinite() && fee.isGreaterThanOrEqualTo(0)\n ? fee\n : new BigNumber(0);\n}\n"]}
1
+ {"version":3,"file":"fiat-direct-musd.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Quote as RampsQuote,\n RampsOrder,\n} from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { TransactionPayStrategy } from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyExecuteRequest,\n PayStrategyGetQuotesRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { prefixError } from '../../utils/error-prefix.js';\nimport { getFiatVaultDisabled } from '../../utils/feature-flags.js';\nimport { submitMoneyAccountVaultDeposit } from '../../utils/ma-vault-deposit.js';\nimport { buildCaipAssetType, getTokenInfo } from '../../utils/token.js';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants.js';\nimport type { FiatQuote } from './types.js';\nimport {\n getNativeTransakRampsFee,\n getRampsQuote,\n getRawSourceAmountFromOrderCryptoAmount,\n resolveSourceAmountRaw,\n validateOrderAsset,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-direct-musd');\nconst DIRECT_MUSD_ERROR_PREFIX = 'Direct mUSD: ';\n\n/**\n * Returns a direct mUSD fiat quote to the Money Account.\n *\n * @param options - Direct quote options.\n * @param options.amountFiat - Fiat amount entered by the user.\n * @param options.fiatPaymentMethod - Selected fiat payment method.\n * @param options.messenger - Controller messenger.\n * @param options.moneyAccountAddress - Money Account receiving the on-ramped mUSD.\n * @param options.requiredToken - Required token from the original Money Account transaction.\n * @param options.transactionId - Transaction ID for state updates and logs.\n * @returns Direct mUSD Fiat quote, or undefined when unavailable.\n */\nexport async function getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod,\n messenger,\n moneyAccountAddress,\n requiredToken,\n transactionId,\n}: {\n amountFiat: string;\n fiatPaymentMethod: string;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n requiredToken: TransactionPayRequiredToken;\n transactionId: string;\n}): Promise<TransactionPayQuote<FiatQuote> | undefined> {\n try {\n const adjustedAmount = Number(amountFiat);\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount for direct mUSD quote');\n }\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n errorMessage: 'No matching ramps quote found for direct mUSD provider',\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n fiatPaymentMethod,\n messenger,\n walletAddress: moneyAccountAddress,\n });\n\n // When Transak Native is the resolved provider, prefer its own quote's fee\n // so the estimate matches what Transak Native will charge. Direct mUSD\n // checkout is fee-inclusive, so request the native quote in that mode.\n const nativeRampsFee = await getNativeTransakRampsFee({\n adjustedAmount,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n fiatPaymentMethod,\n fiatQuote,\n isFeeExcludedFromFiat: false,\n messenger,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n MUSD_MONAD_FIAT_ASSET.chainId,\n MUSD_MONAD_FIAT_ASSET.address,\n );\n },\n transactionId,\n });\n\n log('Direct mUSD fiat quote flow', {\n amountFiat,\n moneyAccountAddress,\n transactionId,\n });\n\n return combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n nativeRampsFee,\n requiredToken,\n });\n } catch (error) {\n log('Direct mUSD fiat quote failed', { error, transactionId });\n return undefined;\n }\n}\n\n/**\n * Detects a direct mUSD Money Account quote from its stored request marker.\n *\n * @param quote - Quote to inspect.\n * @returns True when the quote originated from the direct mUSD fiat path.\n */\nexport function isDirectMusdMoneyAccountQuote(\n quote: Pick<TransactionPayQuote<unknown>, 'request'> | undefined,\n): boolean {\n return quote?.request.isDirectMusdMoneyAccount === true;\n}\n\n/**\n * Submits the direct mUSD post-Ramp path after fiat settlement.\n *\n * @param options - Submit options.\n * @param options.order - Completed fiat order.\n * @param options.request - Strategy execute request.\n * @returns Hash of the submitted direct mUSD transaction, if available.\n */\nexport async function submitDirectMusdAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, transaction } = request;\n\n try {\n validateOrderAsset({\n expectedAsset: MUSD_MONAD_FIAT_ASSET,\n orderCrypto: order.cryptoCurrency,\n transactionId: transaction.id,\n });\n\n const { amountRaw: sourceAmountRaw, fromBlock } =\n await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n walletAddress: transaction.txParams.from as Hex,\n });\n\n return await submitMoneyAccountVaultDeposit({\n fromBlock,\n messenger,\n sourceAmountRaw,\n transaction,\n vaultDisabled: getFiatVaultDisabled(messenger),\n });\n } catch (error) {\n throw prefixError(error, DIRECT_MUSD_ERROR_PREFIX);\n }\n}\n\nfunction combineDirectMusdFiatQuote({\n amountFiat,\n fiatQuote,\n messenger,\n moneyAccountAddress,\n nativeRampsFee,\n requiredToken,\n}: {\n amountFiat: string;\n fiatQuote: RampsQuote;\n messenger: PayStrategyGetQuotesRequest['messenger'];\n moneyAccountAddress: Hex;\n nativeRampsFee: BigNumber | null;\n requiredToken: TransactionPayRequiredToken;\n}): TransactionPayQuote<FiatQuote> {\n const tokenInfo = getTokenInfo(\n messenger,\n MUSD_MONAD_FIAT_ASSET.address,\n MUSD_MONAD_FIAT_ASSET.chainId,\n );\n\n if (!tokenInfo) {\n throw new Error('Unable to resolve mUSD token info for direct fiat quote');\n }\n\n const sourceAmountRaw = getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount: fiatQuote.quote.amountOut,\n decimals: tokenInfo.decimals,\n });\n // Transak Native returns a single total fee, so the aggregator's separate\n // provider/network split collapses: the whole native fee sits in the provider\n // bucket and the source-network fee is zero. The `providerFiat` total stays\n // correct either way.\n const rampsProviderFee = (\n nativeRampsFee ?? getSafeFee(fiatQuote.quote.providerFee)\n ).toString(10);\n const rampsNetworkFee = nativeRampsFee\n ? '0'\n : getSafeFee(fiatQuote.quote.networkFee).toString(10);\n const rampsTotalFee = new BigNumber(rampsProviderFee)\n .plus(rampsNetworkFee)\n .toString(10);\n const targetAmountFiat = getDirectMusdTargetAmountFiat(fiatQuote);\n const sourceAmountHuman = new BigNumber(sourceAmountRaw)\n .shiftedBy(-tokenInfo.decimals)\n .toString(10);\n\n return {\n areFeesIncludedInSourceAmount: true,\n dust: { fiat: '0', usd: '0' },\n estimatedDuration: 0,\n fees: {\n metaMask: { fiat: '0', usd: '0' },\n provider: { fiat: rampsProviderFee, usd: rampsProviderFee },\n providerFiat: { fiat: rampsTotalFee, usd: rampsTotalFee },\n sourceNetwork: {\n estimate: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n max: {\n fiat: rampsNetworkFee,\n human: '0',\n raw: '0',\n usd: rampsNetworkFee,\n },\n },\n targetNetwork: { fiat: '0', usd: '0' },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: undefined,\n },\n request: {\n from: moneyAccountAddress,\n isDirectMusdMoneyAccount: true,\n recipient: moneyAccountAddress,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: MUSD_MONAD_FIAT_ASSET.chainId,\n sourceTokenAddress: MUSD_MONAD_FIAT_ASSET.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: sourceAmountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n },\n sourceAmount: {\n fiat: amountFiat,\n human: sourceAmountHuman,\n raw: sourceAmountRaw,\n usd: amountFiat,\n },\n strategy: TransactionPayStrategy.Fiat,\n targetAmount: { fiat: targetAmountFiat, usd: targetAmountFiat },\n };\n}\n\nfunction getDirectMusdTargetAmountFiat(fiatQuote: RampsQuote): string {\n const amountOutInFiat = new BigNumber(fiatQuote.quote.amountOutInFiat ?? NaN);\n if (amountOutInFiat.isFinite() && amountOutInFiat.isGreaterThanOrEqualTo(0)) {\n return amountOutInFiat.toString(10);\n }\n\n return new BigNumber(fiatQuote.quote.amountOut).toString(10);\n}\n\nfunction getSafeFee(value: BigNumber.Value | undefined): BigNumber {\n const fee = new BigNumber(value ?? 0);\n return fee.isFinite() && fee.isGreaterThanOrEqualTo(0)\n ? fee\n : new BigNumber(0);\n}\n"]}
@@ -113,6 +113,17 @@ async function executeFiatQuotePipeline(request, options) {
113
113
  messenger,
114
114
  walletAddress: rampsWalletAddress,
115
115
  });
116
+ // When Transak Native is the resolved provider, prefer its own quote's fee
117
+ // so the estimate matches what Transak Native will charge. The relay path
118
+ // stays fee-on-top, so request the native quote in the same mode.
119
+ const nativeRampsFee = await (0, utils_js_1.getNativeTransakRampsFee)({
120
+ adjustedAmount,
121
+ fiatAsset,
122
+ fiatPaymentMethod,
123
+ fiatQuote,
124
+ isFeeExcludedFromFiat: true,
125
+ messenger,
126
+ });
116
127
  messenger.call('TransactionPayController:updateFiatPayment', {
117
128
  callback: (fiatPayment) => {
118
129
  fiatPayment.rampsQuote = fiatQuote;
@@ -125,6 +136,7 @@ async function executeFiatQuotePipeline(request, options) {
125
136
  adjustedAmountFiat: adjustedAmountFiat.toString(10),
126
137
  amountFiat,
127
138
  fiatQuote,
139
+ nativeRampsFee,
128
140
  relayQuote,
129
141
  }),
130
142
  ];
@@ -175,6 +187,7 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
175
187
  * @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.
176
188
  * @param params.amountFiat - User-entered fiat amount.
177
189
  * @param params.fiatQuote - Selected ramps quote.
190
+ * @param params.nativeRampsFee - Native Transak fee to use in place of the aggregator ramps fee, or null.
178
191
  * @param params.relayQuote - Estimated relay quote.
179
192
  * @returns A single fiat strategy quote with split fee buckets.
180
193
  * @remarks
@@ -189,8 +202,8 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
189
202
  * Consumed by UI transaction fee row and tooltip MetaMask fee.
190
203
  * - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.
191
204
  */
192
- function combineQuotes({ adjustedAmountFiat, amountFiat, fiatQuote, relayQuote, }) {
193
- const rampsProviderFee = getRampsProviderFee(fiatQuote);
205
+ function combineQuotes({ adjustedAmountFiat, amountFiat, fiatQuote, nativeRampsFee, relayQuote, }) {
206
+ const rampsProviderFee = nativeRampsFee ?? getRampsProviderFee(fiatQuote);
194
207
  const totalProviderFee = new bignumber_js_1.BigNumber(relayQuote.fees.provider.usd)
195
208
  .plus(rampsProviderFee)
196
209
  .toString(10);
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-quotes.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Quote as RampsQuote } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n NATIVE_TOKEN_ADDRESS,\n TransactionPayStrategy,\n} from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { getDirectMoneyMusdEnabled } from '../../utils/feature-flags.js';\nimport {\n buildCaipAssetType,\n computeRawFromFiatAmount,\n getTokenFiatRate,\n getTokenInfo,\n} from '../../utils/token.js';\nimport { getRelayQuotes } from '../relay/relay-quotes.js';\nimport type { RelayQuote } from '../relay/types.js';\nimport type { TransactionPayFiatAsset } from './constants.js';\nimport { getDirectMusdFiatQuote } from './fiat-direct-musd.js';\nimport type { FiatQuote } from './types.js';\nimport {\n deriveFiatAssetForFiatPayment,\n getRampsQuote,\n isMoneyAccountDepositTransaction,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-strategy');\n\ntype FiatQuotePipelineOptions = {\n amountFiat: string;\n fiatAsset: TransactionPayFiatAsset;\n fiatPaymentMethod: string;\n rampsWalletAddress: Hex;\n requiredTokens: TransactionPayRequiredToken[];\n};\n\n/**\n * Fetches MM Pay fiat strategy quotes using a relay-first estimation flow.\n *\n * When the direct-to-mUSD flag is enabled and the transaction is a Money\n * Account deposit, uses direct mUSD params (asset, wallet, recipient).\n * Otherwise, uses the standard ETH flow.\n *\n * @param request - Strategy quotes request.\n * @returns A single combined fiat strategy quote, or an empty array when inputs/quotes are unavailable.\n */\nexport async function getFiatQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const { messenger, transaction } = request;\n\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transaction.id];\n const amountFiat = transactionData?.fiatPayment?.amountFiat;\n const requiredTokens = transactionData?.tokens ?? [];\n\n if (\n !amountFiat ||\n !request.fiatPaymentMethod ||\n requiredTokens.length !== 1\n ) {\n return [];\n }\n\n const useDirectMusd =\n getDirectMoneyMusdEnabled(messenger) &&\n isMoneyAccountDepositTransaction(transaction);\n\n if (useDirectMusd) {\n const requiredToken = requiredTokens[0];\n\n const directQuote = await getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod: request.fiatPaymentMethod,\n messenger,\n moneyAccountAddress: transaction.txParams.from as Hex,\n requiredToken,\n transactionId: transaction.id,\n });\n\n return directQuote ? [directQuote] : [];\n }\n\n return executeFiatQuotePipeline(request, {\n amountFiat,\n fiatAsset: deriveFiatAssetForFiatPayment(transaction, messenger),\n fiatPaymentMethod: request.fiatPaymentMethod,\n rampsWalletAddress: request.from,\n requiredTokens,\n });\n}\n\nasync function executeFiatQuotePipeline(\n request: PayStrategyGetQuotesRequest,\n options: FiatQuotePipelineOptions,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const {\n accountSupports7702,\n from: walletAddress,\n messenger,\n transaction,\n } = request;\n const {\n amountFiat,\n fiatAsset,\n fiatPaymentMethod,\n rampsWalletAddress,\n requiredTokens,\n } = options;\n const transactionId = transaction.id;\n\n try {\n const requiredToken = requiredTokens[0];\n\n const relayRequest = buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n });\n\n if (!relayRequest) {\n throw new Error('Failed to build relay request from fiat amount');\n }\n\n const relayQuotes = await getRelayQuotes({\n accountSupports7702,\n from: walletAddress,\n messenger,\n requests: [relayRequest],\n transaction,\n });\n\n const relayQuote = relayQuotes[0];\n if (!relayQuote) {\n throw new Error('No relay quote available for fiat estimation');\n }\n\n const isSourceNative =\n fiatAsset.address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();\n const gasDeductedFromSource =\n isSourceNative || relayQuote.fees.isSourceGasFeeToken === true;\n\n const relayTotalFeeUsd = gasDeductedFromSource\n ? getRelayTotalFeeUsd(relayQuote)\n : getNonGasRelayFeeUsd(relayQuote);\n const adjustedAmountFiat = new BigNumber(amountFiat).plus(relayTotalFeeUsd);\n\n if (\n !adjustedAmountFiat.isFinite() ||\n !adjustedAmountFiat.gt(0) ||\n !relayTotalFeeUsd.isFinite() ||\n !relayTotalFeeUsd.gte(0)\n ) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n const adjustedAmount = adjustedAmountFiat.toNumber();\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n log('Fiat quote flow', {\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n rampsWalletAddress,\n relayTotalFeeUsd: relayTotalFeeUsd.toString(10),\n sourceAmountRaw: relayRequest.sourceTokenAmount,\n transactionId,\n });\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n fiatAsset,\n fiatPaymentMethod,\n messenger,\n walletAddress: rampsWalletAddress,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n fiatAsset.chainId,\n fiatAsset.address,\n );\n },\n transactionId,\n });\n\n return [\n combineQuotes({\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n fiatQuote,\n relayQuote,\n }),\n ];\n } catch (error) {\n log('Failed to fetch fiat quotes', { error, transactionId });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment) => {\n fiatPayment.rampsQuote = undefined;\n },\n transactionId,\n });\n }\n\n return [];\n}\n\nfunction buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n}: {\n amountFiat: string;\n fiatAsset: {\n address: Hex;\n chainId: Hex;\n };\n messenger: PayStrategyGetQuotesRequest['messenger'];\n requiredToken: TransactionPayRequiredToken;\n walletAddress: Hex;\n}): QuoteRequest | undefined {\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!sourceFiatRate) {\n return undefined;\n }\n\n const tokenInfo = getTokenInfo(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!tokenInfo) {\n return undefined;\n }\n\n const sourceAmountRaw = computeRawFromFiatAmount(\n amountFiat,\n tokenInfo.decimals,\n sourceFiatRate.usdRate,\n );\n\n if (!sourceAmountRaw) {\n return undefined;\n }\n\n return {\n from: walletAddress,\n // Force EXACT_INPUT mode: source amount is pre-calculated from the fiat\n // amount, so the relay should treat it as a fixed input rather than\n // computing it from the target.\n isPostQuote: true,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: fiatAsset.chainId,\n sourceTokenAddress: fiatAsset.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: requiredToken.amountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n };\n}\n\n/**\n * Combines fiat and relay legs into a single MM Pay fiat strategy quote.\n *\n * @param params - Combined quote inputs.\n * @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.\n * @param params.amountFiat - User-entered fiat amount.\n * @param params.fiatQuote - Selected ramps quote.\n * @param params.relayQuote - Estimated relay quote.\n * @returns A single fiat strategy quote with split fee buckets.\n * @remarks\n * Fee mapping contract for MM Pay Fiat strategy:\n * - `fees.provider`: Total provider fee (relay provider/swap fee + ramps provider/network fee).\n * Consumed by UI transaction fee row and tooltip provider fee.\n * - `fees.providerFiat`: Fiat on-ramp provider fees only (`providerFee + networkFee` from ramps quote).\n * Optional breakdown; client can derive relay portion via `provider - providerFiat`.\n * - `fees.sourceNetwork` / `fees.targetNetwork`: Relay settlement network fees.\n * Consumed by UI transaction fee row and tooltip network fee.\n * - `fees.metaMask`: MM Pay fee (currently 100 bps over `amountFiat + adjustedAmountFiat`).\n * Consumed by UI transaction fee row and tooltip MetaMask fee.\n * - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.\n */\nfunction combineQuotes({\n adjustedAmountFiat,\n amountFiat,\n fiatQuote,\n relayQuote,\n}: {\n adjustedAmountFiat: string;\n amountFiat: string;\n fiatQuote: RampsQuote;\n relayQuote: TransactionPayQuote<RelayQuote>;\n}): TransactionPayQuote<FiatQuote> {\n const rampsProviderFee = getRampsProviderFee(fiatQuote);\n const totalProviderFee = new BigNumber(relayQuote.fees.provider.usd)\n .plus(rampsProviderFee)\n .toString(10);\n const rampsProviderFeeStr = rampsProviderFee.toString(10);\n const metaMaskFee = getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n }).toString(10);\n\n return {\n ...relayQuote,\n fees: {\n ...relayQuote.fees,\n metaMask: {\n fiat: metaMaskFee,\n usd: metaMaskFee,\n },\n provider: {\n fiat: totalProviderFee,\n usd: totalProviderFee,\n },\n providerFiat: {\n fiat: rampsProviderFeeStr,\n usd: rampsProviderFeeStr,\n },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: relayQuote.original,\n },\n strategy: TransactionPayStrategy.Fiat,\n };\n}\n\n/**\n * Ramps providers handle network gas fees themselves but report them separately\n * as `networkFee` alongside their `providerFee`. We combine both into a single\n * ramps provider fee for the `providerFiat` breakdown.\n *\n * @param fiatQuote - The ramps quote containing provider and network fees.\n * @returns Combined ramps provider fee as a BigNumber.\n */\nfunction getRampsProviderFee(fiatQuote: RampsQuote): BigNumber {\n return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(\n fiatQuote.quote.networkFee ?? 0,\n );\n}\n\nfunction getRelayTotalFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.sourceNetwork.estimate.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getNonGasRelayFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n}: {\n adjustedAmountFiat: BigNumber.Value;\n amountFiat: BigNumber.Value;\n}): BigNumber {\n return new BigNumber(amountFiat).plus(adjustedAmountFiat).dividedBy(100);\n}\n"]}
1
+ {"version":3,"file":"fiat-quotes.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Quote as RampsQuote } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n NATIVE_TOKEN_ADDRESS,\n TransactionPayStrategy,\n} from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { getDirectMoneyMusdEnabled } from '../../utils/feature-flags.js';\nimport {\n buildCaipAssetType,\n computeRawFromFiatAmount,\n getTokenFiatRate,\n getTokenInfo,\n} from '../../utils/token.js';\nimport { getRelayQuotes } from '../relay/relay-quotes.js';\nimport type { RelayQuote } from '../relay/types.js';\nimport type { TransactionPayFiatAsset } from './constants.js';\nimport { getDirectMusdFiatQuote } from './fiat-direct-musd.js';\nimport type { FiatQuote } from './types.js';\nimport {\n deriveFiatAssetForFiatPayment,\n getNativeTransakRampsFee,\n getRampsQuote,\n isMoneyAccountDepositTransaction,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-strategy');\n\ntype FiatQuotePipelineOptions = {\n amountFiat: string;\n fiatAsset: TransactionPayFiatAsset;\n fiatPaymentMethod: string;\n rampsWalletAddress: Hex;\n requiredTokens: TransactionPayRequiredToken[];\n};\n\n/**\n * Fetches MM Pay fiat strategy quotes using a relay-first estimation flow.\n *\n * When the direct-to-mUSD flag is enabled and the transaction is a Money\n * Account deposit, uses direct mUSD params (asset, wallet, recipient).\n * Otherwise, uses the standard ETH flow.\n *\n * @param request - Strategy quotes request.\n * @returns A single combined fiat strategy quote, or an empty array when inputs/quotes are unavailable.\n */\nexport async function getFiatQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const { messenger, transaction } = request;\n\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transaction.id];\n const amountFiat = transactionData?.fiatPayment?.amountFiat;\n const requiredTokens = transactionData?.tokens ?? [];\n\n if (\n !amountFiat ||\n !request.fiatPaymentMethod ||\n requiredTokens.length !== 1\n ) {\n return [];\n }\n\n const useDirectMusd =\n getDirectMoneyMusdEnabled(messenger) &&\n isMoneyAccountDepositTransaction(transaction);\n\n if (useDirectMusd) {\n const requiredToken = requiredTokens[0];\n\n const directQuote = await getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod: request.fiatPaymentMethod,\n messenger,\n moneyAccountAddress: transaction.txParams.from as Hex,\n requiredToken,\n transactionId: transaction.id,\n });\n\n return directQuote ? [directQuote] : [];\n }\n\n return executeFiatQuotePipeline(request, {\n amountFiat,\n fiatAsset: deriveFiatAssetForFiatPayment(transaction, messenger),\n fiatPaymentMethod: request.fiatPaymentMethod,\n rampsWalletAddress: request.from,\n requiredTokens,\n });\n}\n\nasync function executeFiatQuotePipeline(\n request: PayStrategyGetQuotesRequest,\n options: FiatQuotePipelineOptions,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const {\n accountSupports7702,\n from: walletAddress,\n messenger,\n transaction,\n } = request;\n const {\n amountFiat,\n fiatAsset,\n fiatPaymentMethod,\n rampsWalletAddress,\n requiredTokens,\n } = options;\n const transactionId = transaction.id;\n\n try {\n const requiredToken = requiredTokens[0];\n\n const relayRequest = buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n });\n\n if (!relayRequest) {\n throw new Error('Failed to build relay request from fiat amount');\n }\n\n const relayQuotes = await getRelayQuotes({\n accountSupports7702,\n from: walletAddress,\n messenger,\n requests: [relayRequest],\n transaction,\n });\n\n const relayQuote = relayQuotes[0];\n if (!relayQuote) {\n throw new Error('No relay quote available for fiat estimation');\n }\n\n const isSourceNative =\n fiatAsset.address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();\n const gasDeductedFromSource =\n isSourceNative || relayQuote.fees.isSourceGasFeeToken === true;\n\n const relayTotalFeeUsd = gasDeductedFromSource\n ? getRelayTotalFeeUsd(relayQuote)\n : getNonGasRelayFeeUsd(relayQuote);\n const adjustedAmountFiat = new BigNumber(amountFiat).plus(relayTotalFeeUsd);\n\n if (\n !adjustedAmountFiat.isFinite() ||\n !adjustedAmountFiat.gt(0) ||\n !relayTotalFeeUsd.isFinite() ||\n !relayTotalFeeUsd.gte(0)\n ) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n const adjustedAmount = adjustedAmountFiat.toNumber();\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n log('Fiat quote flow', {\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n rampsWalletAddress,\n relayTotalFeeUsd: relayTotalFeeUsd.toString(10),\n sourceAmountRaw: relayRequest.sourceTokenAmount,\n transactionId,\n });\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n fiatAsset,\n fiatPaymentMethod,\n messenger,\n walletAddress: rampsWalletAddress,\n });\n\n // When Transak Native is the resolved provider, prefer its own quote's fee\n // so the estimate matches what Transak Native will charge. The relay path\n // stays fee-on-top, so request the native quote in the same mode.\n const nativeRampsFee = await getNativeTransakRampsFee({\n adjustedAmount,\n fiatAsset,\n fiatPaymentMethod,\n fiatQuote,\n isFeeExcludedFromFiat: true,\n messenger,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n fiatAsset.chainId,\n fiatAsset.address,\n );\n },\n transactionId,\n });\n\n return [\n combineQuotes({\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n fiatQuote,\n nativeRampsFee,\n relayQuote,\n }),\n ];\n } catch (error) {\n log('Failed to fetch fiat quotes', { error, transactionId });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment) => {\n fiatPayment.rampsQuote = undefined;\n },\n transactionId,\n });\n }\n\n return [];\n}\n\nfunction buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n}: {\n amountFiat: string;\n fiatAsset: {\n address: Hex;\n chainId: Hex;\n };\n messenger: PayStrategyGetQuotesRequest['messenger'];\n requiredToken: TransactionPayRequiredToken;\n walletAddress: Hex;\n}): QuoteRequest | undefined {\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!sourceFiatRate) {\n return undefined;\n }\n\n const tokenInfo = getTokenInfo(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!tokenInfo) {\n return undefined;\n }\n\n const sourceAmountRaw = computeRawFromFiatAmount(\n amountFiat,\n tokenInfo.decimals,\n sourceFiatRate.usdRate,\n );\n\n if (!sourceAmountRaw) {\n return undefined;\n }\n\n return {\n from: walletAddress,\n // Force EXACT_INPUT mode: source amount is pre-calculated from the fiat\n // amount, so the relay should treat it as a fixed input rather than\n // computing it from the target.\n isPostQuote: true,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: fiatAsset.chainId,\n sourceTokenAddress: fiatAsset.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: requiredToken.amountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n };\n}\n\n/**\n * Combines fiat and relay legs into a single MM Pay fiat strategy quote.\n *\n * @param params - Combined quote inputs.\n * @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.\n * @param params.amountFiat - User-entered fiat amount.\n * @param params.fiatQuote - Selected ramps quote.\n * @param params.nativeRampsFee - Native Transak fee to use in place of the aggregator ramps fee, or null.\n * @param params.relayQuote - Estimated relay quote.\n * @returns A single fiat strategy quote with split fee buckets.\n * @remarks\n * Fee mapping contract for MM Pay Fiat strategy:\n * - `fees.provider`: Total provider fee (relay provider/swap fee + ramps provider/network fee).\n * Consumed by UI transaction fee row and tooltip provider fee.\n * - `fees.providerFiat`: Fiat on-ramp provider fees only (`providerFee + networkFee` from ramps quote).\n * Optional breakdown; client can derive relay portion via `provider - providerFiat`.\n * - `fees.sourceNetwork` / `fees.targetNetwork`: Relay settlement network fees.\n * Consumed by UI transaction fee row and tooltip network fee.\n * - `fees.metaMask`: MM Pay fee (currently 100 bps over `amountFiat + adjustedAmountFiat`).\n * Consumed by UI transaction fee row and tooltip MetaMask fee.\n * - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.\n */\nfunction combineQuotes({\n adjustedAmountFiat,\n amountFiat,\n fiatQuote,\n nativeRampsFee,\n relayQuote,\n}: {\n adjustedAmountFiat: string;\n amountFiat: string;\n fiatQuote: RampsQuote;\n nativeRampsFee: BigNumber | null;\n relayQuote: TransactionPayQuote<RelayQuote>;\n}): TransactionPayQuote<FiatQuote> {\n const rampsProviderFee = nativeRampsFee ?? getRampsProviderFee(fiatQuote);\n const totalProviderFee = new BigNumber(relayQuote.fees.provider.usd)\n .plus(rampsProviderFee)\n .toString(10);\n const rampsProviderFeeStr = rampsProviderFee.toString(10);\n const metaMaskFee = getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n }).toString(10);\n\n return {\n ...relayQuote,\n fees: {\n ...relayQuote.fees,\n metaMask: {\n fiat: metaMaskFee,\n usd: metaMaskFee,\n },\n provider: {\n fiat: totalProviderFee,\n usd: totalProviderFee,\n },\n providerFiat: {\n fiat: rampsProviderFeeStr,\n usd: rampsProviderFeeStr,\n },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: relayQuote.original,\n },\n strategy: TransactionPayStrategy.Fiat,\n };\n}\n\n/**\n * Ramps providers handle network gas fees themselves but report them separately\n * as `networkFee` alongside their `providerFee`. We combine both into a single\n * ramps provider fee for the `providerFiat` breakdown.\n *\n * @param fiatQuote - The ramps quote containing provider and network fees.\n * @returns Combined ramps provider fee as a BigNumber.\n */\nfunction getRampsProviderFee(fiatQuote: RampsQuote): BigNumber {\n return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(\n fiatQuote.quote.networkFee ?? 0,\n );\n}\n\nfunction getRelayTotalFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.sourceNetwork.estimate.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getNonGasRelayFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n}: {\n adjustedAmountFiat: BigNumber.Value;\n amountFiat: BigNumber.Value;\n}): BigNumber {\n return new BigNumber(amountFiat).plus(adjustedAmountFiat).dividedBy(100);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-quotes.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,wBAAuB;AAYxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAiB5C;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CA0C3C"}
1
+ {"version":3,"file":"fiat-quotes.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,wBAAuB;AAYxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAkB5C;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CA0C3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-quotes.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,wBAAuB;AAYxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAiB5C;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CA0C3C"}
1
+ {"version":3,"file":"fiat-quotes.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,wBAAuB;AAYxB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAmB;AAkB5C;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CA0C3C"}
@@ -6,7 +6,7 @@ import { getDirectMoneyMusdEnabled } from "../../utils/feature-flags.mjs";
6
6
  import { buildCaipAssetType, computeRawFromFiatAmount, getTokenFiatRate, getTokenInfo } from "../../utils/token.mjs";
7
7
  import { getRelayQuotes } from "../relay/relay-quotes.mjs";
8
8
  import { getDirectMusdFiatQuote } from "./fiat-direct-musd.mjs";
9
- import { deriveFiatAssetForFiatPayment, getRampsQuote, isMoneyAccountDepositTransaction } from "./utils.mjs";
9
+ import { deriveFiatAssetForFiatPayment, getNativeTransakRampsFee, getRampsQuote, isMoneyAccountDepositTransaction } from "./utils.mjs";
10
10
  const log = createModuleLogger(projectLogger, 'fiat-strategy');
11
11
  /**
12
12
  * Fetches MM Pay fiat strategy quotes using a relay-first estimation flow.
@@ -109,6 +109,17 @@ async function executeFiatQuotePipeline(request, options) {
109
109
  messenger,
110
110
  walletAddress: rampsWalletAddress,
111
111
  });
112
+ // When Transak Native is the resolved provider, prefer its own quote's fee
113
+ // so the estimate matches what Transak Native will charge. The relay path
114
+ // stays fee-on-top, so request the native quote in the same mode.
115
+ const nativeRampsFee = await getNativeTransakRampsFee({
116
+ adjustedAmount,
117
+ fiatAsset,
118
+ fiatPaymentMethod,
119
+ fiatQuote,
120
+ isFeeExcludedFromFiat: true,
121
+ messenger,
122
+ });
112
123
  messenger.call('TransactionPayController:updateFiatPayment', {
113
124
  callback: (fiatPayment) => {
114
125
  fiatPayment.rampsQuote = fiatQuote;
@@ -121,6 +132,7 @@ async function executeFiatQuotePipeline(request, options) {
121
132
  adjustedAmountFiat: adjustedAmountFiat.toString(10),
122
133
  amountFiat,
123
134
  fiatQuote,
135
+ nativeRampsFee,
124
136
  relayQuote,
125
137
  }),
126
138
  ];
@@ -171,6 +183,7 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
171
183
  * @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.
172
184
  * @param params.amountFiat - User-entered fiat amount.
173
185
  * @param params.fiatQuote - Selected ramps quote.
186
+ * @param params.nativeRampsFee - Native Transak fee to use in place of the aggregator ramps fee, or null.
174
187
  * @param params.relayQuote - Estimated relay quote.
175
188
  * @returns A single fiat strategy quote with split fee buckets.
176
189
  * @remarks
@@ -185,8 +198,8 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
185
198
  * Consumed by UI transaction fee row and tooltip MetaMask fee.
186
199
  * - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.
187
200
  */
188
- function combineQuotes({ adjustedAmountFiat, amountFiat, fiatQuote, relayQuote, }) {
189
- const rampsProviderFee = getRampsProviderFee(fiatQuote);
201
+ function combineQuotes({ adjustedAmountFiat, amountFiat, fiatQuote, nativeRampsFee, relayQuote, }) {
202
+ const rampsProviderFee = nativeRampsFee ?? getRampsProviderFee(fiatQuote);
190
203
  const totalProviderFee = new BigNumber(relayQuote.fees.provider.usd)
191
204
  .plus(rampsProviderFee)
192
205
  .toString(10);
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-quotes.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB;AACrD,OAAO,EAAE,SAAS,EAAE,qBAAqB;AAEzC,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACvB,4BAA2B;AAC5B,OAAO,EAAE,aAAa,EAAE,yBAAwB;AAQhD,OAAO,EAAE,yBAAyB,EAAE,sCAAqC;AACzE,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,gBAAgB,EAChB,YAAY,EACb,8BAA6B;AAC9B,OAAO,EAAE,cAAc,EAAE,kCAAiC;AAG1D,OAAO,EAAE,sBAAsB,EAAE,+BAA8B;AAE/D,OAAO,EACL,6BAA6B,EAC7B,aAAa,EACb,gCAAgC,EACjC,oBAAmB;AAEpB,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAU/D;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAoC;IAEpC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAE3C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAClE,MAAM,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,eAAe,EAAE,WAAW,EAAE,UAAU,CAAC;IAC5D,MAAM,cAAc,GAAG,eAAe,EAAE,MAAM,IAAI,EAAE,CAAC;IAErD,IACE,CAAC,UAAU;QACX,CAAC,OAAO,CAAC,iBAAiB;QAC1B,cAAc,CAAC,MAAM,KAAK,CAAC,EAC3B,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,aAAa,GACjB,yBAAyB,CAAC,SAAS,CAAC;QACpC,gCAAgC,CAAC,WAAW,CAAC,CAAC;IAEhD,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAC;YAC/C,UAAU;YACV,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;YAC5C,SAAS;YACT,mBAAmB,EAAE,WAAW,CAAC,QAAQ,CAAC,IAAW;YACrD,aAAa;YACb,aAAa,EAAE,WAAW,CAAC,EAAE;SAC9B,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,CAAC;IAED,OAAO,wBAAwB,CAAC,OAAO,EAAE;QACvC,UAAU;QACV,SAAS,EAAE,6BAA6B,CAAC,WAAW,EAAE,SAAS,CAAC;QAChE,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,kBAAkB,EAAE,OAAO,CAAC,IAAI;QAChC,cAAc;KACf,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,OAAoC,EACpC,OAAiC;IAEjC,MAAM,EACJ,mBAAmB,EACnB,IAAI,EAAE,aAAa,EACnB,SAAS,EACT,WAAW,GACZ,GAAG,OAAO,CAAC;IACZ,MAAM,EACJ,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,GACf,GAAG,OAAO,CAAC;IACZ,MAAM,aAAa,GAAG,WAAW,CAAC,EAAE,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,YAAY,GAAG,+BAA+B,CAAC;YACnD,UAAU;YACV,SAAS;YACT,SAAS;YACT,aAAa;YACb,aAAa;SACd,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC;YACvC,mBAAmB;YACnB,IAAI,EAAE,aAAa;YACnB,SAAS;YACT,QAAQ,EAAE,CAAC,YAAY,CAAC;YACxB,WAAW;SACZ,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAED,MAAM,cAAc,GAClB,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,oBAAoB,CAAC,WAAW,EAAE,CAAC;QACzE,MAAM,qBAAqB,GACzB,cAAc,IAAI,UAAU,CAAC,IAAI,CAAC,mBAAmB,KAAK,IAAI,CAAC;QAEjE,MAAM,gBAAgB,GAAG,qBAAqB;YAC5C,CAAC,CAAC,mBAAmB,CAAC,UAAU,CAAC;YACjC,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,kBAAkB,GAAG,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAE5E,IACE,CAAC,kBAAkB,CAAC,QAAQ,EAAE;YAC9B,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC;YACzB,CAAC,gBAAgB,CAAC,QAAQ,EAAE;YAC5B,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EACxB,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,cAAc,GAAG,kBAAkB,CAAC,QAAQ,EAAE,CAAC;QAErD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QAED,GAAG,CAAC,iBAAiB,EAAE;YACrB,kBAAkB,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnD,UAAU;YACV,kBAAkB;YAClB,gBAAgB,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,eAAe,EAAE,YAAY,CAAC,iBAAiB;YAC/C,aAAa;SACd,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC;YACpC,cAAc;YACd,SAAS;YACT,iBAAiB;YACjB,SAAS;YACT,aAAa,EAAE,kBAAkB;SAClC,CAAC,CAAC;QAEH,SAAS,CAAC,IAAI,CAAC,4CAA4C,EAAE;YAC3D,QAAQ,EAAE,CAAC,WAAmC,EAAE,EAAE;gBAChD,WAAW,CAAC,UAAU,GAAG,SAAS,CAAC;gBACnC,WAAW,CAAC,WAAW,GAAG,kBAAkB,CAC1C,SAAS,CAAC,OAAO,EACjB,SAAS,CAAC,OAAO,CAClB,CAAC;YACJ,CAAC;YACD,aAAa;SACd,CAAC,CAAC;QAEH,OAAO;YACL,aAAa,CAAC;gBACZ,kBAAkB,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnD,UAAU;gBACV,SAAS;gBACT,UAAU;aACX,CAAC;SACH,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;QAE7D,SAAS,CAAC,IAAI,CAAC,4CAA4C,EAAE;YAC3D,QAAQ,EAAE,CAAC,WAAW,EAAE,EAAE;gBACxB,WAAW,CAAC,UAAU,GAAG,SAAS,CAAC;YACrC,CAAC;YACD,aAAa;SACd,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,+BAA+B,CAAC,EACvC,UAAU,EACV,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,GAUd;IACC,MAAM,cAAc,GAAG,gBAAgB,CACrC,SAAS,EACT,SAAS,CAAC,OAAO,EACjB,SAAS,CAAC,OAAO,CAClB,CAAC;IAEF,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAG,YAAY,CAC5B,SAAS,EACT,SAAS,CAAC,OAAO,EACjB,SAAS,CAAC,OAAO,CAClB,CAAC;IAEF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,eAAe,GAAG,wBAAwB,CAC9C,UAAU,EACV,SAAS,CAAC,QAAQ,EAClB,cAAc,CAAC,OAAO,CACvB,CAAC;IAEF,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,wEAAwE;QACxE,oEAAoE;QACpE,gCAAgC;QAChC,WAAW,EAAE,IAAI;QACjB,gBAAgB,EAAE,eAAe;QACjC,aAAa,EAAE,SAAS,CAAC,OAAO;QAChC,kBAAkB,EAAE,SAAS,CAAC,OAAO;QACrC,iBAAiB,EAAE,eAAe;QAClC,mBAAmB,EAAE,aAAa,CAAC,SAAS;QAC5C,aAAa,EAAE,aAAa,CAAC,OAAO;QACpC,kBAAkB,EAAE,aAAa,CAAC,OAAO;KAC1C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,aAAa,CAAC,EACrB,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,UAAU,GAMX;IACC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,gBAAgB,GAAG,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;SACjE,IAAI,CAAC,gBAAgB,CAAC;SACtB,QAAQ,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,cAAc,CAAC;QACjC,kBAAkB;QAClB,UAAU;KACX,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEhB,OAAO;QACL,GAAG,UAAU;QACb,IAAI,EAAE;YACJ,GAAG,UAAU,CAAC,IAAI;YAClB,QAAQ,EAAE;gBACR,IAAI,EAAE,WAAW;gBACjB,GAAG,EAAE,WAAW;aACjB;YACD,QAAQ,EAAE;gBACR,IAAI,EAAE,gBAAgB;gBACtB,GAAG,EAAE,gBAAgB;aACtB;YACD,YAAY,EAAE;gBACZ,IAAI,EAAE,mBAAmB;gBACzB,GAAG,EAAE,mBAAmB;aACzB;SACF;QACD,QAAQ,EAAE;YACR,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,UAAU,CAAC,QAAQ;SAChC;QACD,QAAQ,EAAE,sBAAsB,CAAC,IAAI;KACtC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,SAAqB;IAChD,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,IAAI,CACzD,SAAS,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAChC,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAC1B,UAA2C;IAE3C,OAAO,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;SAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC;SAChD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;SACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,oBAAoB,CAC3B,UAA2C;IAE3C,OAAO,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;SAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;SACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,cAAc,CAAC,EACtB,kBAAkB,EAClB,UAAU,GAIX;IACC,OAAO,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["import type { Quote as RampsQuote } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n NATIVE_TOKEN_ADDRESS,\n TransactionPayStrategy,\n} from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { getDirectMoneyMusdEnabled } from '../../utils/feature-flags.js';\nimport {\n buildCaipAssetType,\n computeRawFromFiatAmount,\n getTokenFiatRate,\n getTokenInfo,\n} from '../../utils/token.js';\nimport { getRelayQuotes } from '../relay/relay-quotes.js';\nimport type { RelayQuote } from '../relay/types.js';\nimport type { TransactionPayFiatAsset } from './constants.js';\nimport { getDirectMusdFiatQuote } from './fiat-direct-musd.js';\nimport type { FiatQuote } from './types.js';\nimport {\n deriveFiatAssetForFiatPayment,\n getRampsQuote,\n isMoneyAccountDepositTransaction,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-strategy');\n\ntype FiatQuotePipelineOptions = {\n amountFiat: string;\n fiatAsset: TransactionPayFiatAsset;\n fiatPaymentMethod: string;\n rampsWalletAddress: Hex;\n requiredTokens: TransactionPayRequiredToken[];\n};\n\n/**\n * Fetches MM Pay fiat strategy quotes using a relay-first estimation flow.\n *\n * When the direct-to-mUSD flag is enabled and the transaction is a Money\n * Account deposit, uses direct mUSD params (asset, wallet, recipient).\n * Otherwise, uses the standard ETH flow.\n *\n * @param request - Strategy quotes request.\n * @returns A single combined fiat strategy quote, or an empty array when inputs/quotes are unavailable.\n */\nexport async function getFiatQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const { messenger, transaction } = request;\n\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transaction.id];\n const amountFiat = transactionData?.fiatPayment?.amountFiat;\n const requiredTokens = transactionData?.tokens ?? [];\n\n if (\n !amountFiat ||\n !request.fiatPaymentMethod ||\n requiredTokens.length !== 1\n ) {\n return [];\n }\n\n const useDirectMusd =\n getDirectMoneyMusdEnabled(messenger) &&\n isMoneyAccountDepositTransaction(transaction);\n\n if (useDirectMusd) {\n const requiredToken = requiredTokens[0];\n\n const directQuote = await getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod: request.fiatPaymentMethod,\n messenger,\n moneyAccountAddress: transaction.txParams.from as Hex,\n requiredToken,\n transactionId: transaction.id,\n });\n\n return directQuote ? [directQuote] : [];\n }\n\n return executeFiatQuotePipeline(request, {\n amountFiat,\n fiatAsset: deriveFiatAssetForFiatPayment(transaction, messenger),\n fiatPaymentMethod: request.fiatPaymentMethod,\n rampsWalletAddress: request.from,\n requiredTokens,\n });\n}\n\nasync function executeFiatQuotePipeline(\n request: PayStrategyGetQuotesRequest,\n options: FiatQuotePipelineOptions,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const {\n accountSupports7702,\n from: walletAddress,\n messenger,\n transaction,\n } = request;\n const {\n amountFiat,\n fiatAsset,\n fiatPaymentMethod,\n rampsWalletAddress,\n requiredTokens,\n } = options;\n const transactionId = transaction.id;\n\n try {\n const requiredToken = requiredTokens[0];\n\n const relayRequest = buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n });\n\n if (!relayRequest) {\n throw new Error('Failed to build relay request from fiat amount');\n }\n\n const relayQuotes = await getRelayQuotes({\n accountSupports7702,\n from: walletAddress,\n messenger,\n requests: [relayRequest],\n transaction,\n });\n\n const relayQuote = relayQuotes[0];\n if (!relayQuote) {\n throw new Error('No relay quote available for fiat estimation');\n }\n\n const isSourceNative =\n fiatAsset.address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();\n const gasDeductedFromSource =\n isSourceNative || relayQuote.fees.isSourceGasFeeToken === true;\n\n const relayTotalFeeUsd = gasDeductedFromSource\n ? getRelayTotalFeeUsd(relayQuote)\n : getNonGasRelayFeeUsd(relayQuote);\n const adjustedAmountFiat = new BigNumber(amountFiat).plus(relayTotalFeeUsd);\n\n if (\n !adjustedAmountFiat.isFinite() ||\n !adjustedAmountFiat.gt(0) ||\n !relayTotalFeeUsd.isFinite() ||\n !relayTotalFeeUsd.gte(0)\n ) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n const adjustedAmount = adjustedAmountFiat.toNumber();\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n log('Fiat quote flow', {\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n rampsWalletAddress,\n relayTotalFeeUsd: relayTotalFeeUsd.toString(10),\n sourceAmountRaw: relayRequest.sourceTokenAmount,\n transactionId,\n });\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n fiatAsset,\n fiatPaymentMethod,\n messenger,\n walletAddress: rampsWalletAddress,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n fiatAsset.chainId,\n fiatAsset.address,\n );\n },\n transactionId,\n });\n\n return [\n combineQuotes({\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n fiatQuote,\n relayQuote,\n }),\n ];\n } catch (error) {\n log('Failed to fetch fiat quotes', { error, transactionId });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment) => {\n fiatPayment.rampsQuote = undefined;\n },\n transactionId,\n });\n }\n\n return [];\n}\n\nfunction buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n}: {\n amountFiat: string;\n fiatAsset: {\n address: Hex;\n chainId: Hex;\n };\n messenger: PayStrategyGetQuotesRequest['messenger'];\n requiredToken: TransactionPayRequiredToken;\n walletAddress: Hex;\n}): QuoteRequest | undefined {\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!sourceFiatRate) {\n return undefined;\n }\n\n const tokenInfo = getTokenInfo(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!tokenInfo) {\n return undefined;\n }\n\n const sourceAmountRaw = computeRawFromFiatAmount(\n amountFiat,\n tokenInfo.decimals,\n sourceFiatRate.usdRate,\n );\n\n if (!sourceAmountRaw) {\n return undefined;\n }\n\n return {\n from: walletAddress,\n // Force EXACT_INPUT mode: source amount is pre-calculated from the fiat\n // amount, so the relay should treat it as a fixed input rather than\n // computing it from the target.\n isPostQuote: true,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: fiatAsset.chainId,\n sourceTokenAddress: fiatAsset.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: requiredToken.amountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n };\n}\n\n/**\n * Combines fiat and relay legs into a single MM Pay fiat strategy quote.\n *\n * @param params - Combined quote inputs.\n * @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.\n * @param params.amountFiat - User-entered fiat amount.\n * @param params.fiatQuote - Selected ramps quote.\n * @param params.relayQuote - Estimated relay quote.\n * @returns A single fiat strategy quote with split fee buckets.\n * @remarks\n * Fee mapping contract for MM Pay Fiat strategy:\n * - `fees.provider`: Total provider fee (relay provider/swap fee + ramps provider/network fee).\n * Consumed by UI transaction fee row and tooltip provider fee.\n * - `fees.providerFiat`: Fiat on-ramp provider fees only (`providerFee + networkFee` from ramps quote).\n * Optional breakdown; client can derive relay portion via `provider - providerFiat`.\n * - `fees.sourceNetwork` / `fees.targetNetwork`: Relay settlement network fees.\n * Consumed by UI transaction fee row and tooltip network fee.\n * - `fees.metaMask`: MM Pay fee (currently 100 bps over `amountFiat + adjustedAmountFiat`).\n * Consumed by UI transaction fee row and tooltip MetaMask fee.\n * - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.\n */\nfunction combineQuotes({\n adjustedAmountFiat,\n amountFiat,\n fiatQuote,\n relayQuote,\n}: {\n adjustedAmountFiat: string;\n amountFiat: string;\n fiatQuote: RampsQuote;\n relayQuote: TransactionPayQuote<RelayQuote>;\n}): TransactionPayQuote<FiatQuote> {\n const rampsProviderFee = getRampsProviderFee(fiatQuote);\n const totalProviderFee = new BigNumber(relayQuote.fees.provider.usd)\n .plus(rampsProviderFee)\n .toString(10);\n const rampsProviderFeeStr = rampsProviderFee.toString(10);\n const metaMaskFee = getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n }).toString(10);\n\n return {\n ...relayQuote,\n fees: {\n ...relayQuote.fees,\n metaMask: {\n fiat: metaMaskFee,\n usd: metaMaskFee,\n },\n provider: {\n fiat: totalProviderFee,\n usd: totalProviderFee,\n },\n providerFiat: {\n fiat: rampsProviderFeeStr,\n usd: rampsProviderFeeStr,\n },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: relayQuote.original,\n },\n strategy: TransactionPayStrategy.Fiat,\n };\n}\n\n/**\n * Ramps providers handle network gas fees themselves but report them separately\n * as `networkFee` alongside their `providerFee`. We combine both into a single\n * ramps provider fee for the `providerFiat` breakdown.\n *\n * @param fiatQuote - The ramps quote containing provider and network fees.\n * @returns Combined ramps provider fee as a BigNumber.\n */\nfunction getRampsProviderFee(fiatQuote: RampsQuote): BigNumber {\n return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(\n fiatQuote.quote.networkFee ?? 0,\n );\n}\n\nfunction getRelayTotalFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.sourceNetwork.estimate.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getNonGasRelayFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n}: {\n adjustedAmountFiat: BigNumber.Value;\n amountFiat: BigNumber.Value;\n}): BigNumber {\n return new BigNumber(amountFiat).plus(adjustedAmountFiat).dividedBy(100);\n}\n"]}
1
+ {"version":3,"file":"fiat-quotes.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Quote as RampsQuote } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n NATIVE_TOKEN_ADDRESS,\n TransactionPayStrategy,\n} from '../../constants.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionFiatPayment,\n TransactionPayRequiredToken,\n TransactionPayQuote,\n} from '../../types.js';\nimport { getDirectMoneyMusdEnabled } from '../../utils/feature-flags.js';\nimport {\n buildCaipAssetType,\n computeRawFromFiatAmount,\n getTokenFiatRate,\n getTokenInfo,\n} from '../../utils/token.js';\nimport { getRelayQuotes } from '../relay/relay-quotes.js';\nimport type { RelayQuote } from '../relay/types.js';\nimport type { TransactionPayFiatAsset } from './constants.js';\nimport { getDirectMusdFiatQuote } from './fiat-direct-musd.js';\nimport type { FiatQuote } from './types.js';\nimport {\n deriveFiatAssetForFiatPayment,\n getNativeTransakRampsFee,\n getRampsQuote,\n isMoneyAccountDepositTransaction,\n} from './utils.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-strategy');\n\ntype FiatQuotePipelineOptions = {\n amountFiat: string;\n fiatAsset: TransactionPayFiatAsset;\n fiatPaymentMethod: string;\n rampsWalletAddress: Hex;\n requiredTokens: TransactionPayRequiredToken[];\n};\n\n/**\n * Fetches MM Pay fiat strategy quotes using a relay-first estimation flow.\n *\n * When the direct-to-mUSD flag is enabled and the transaction is a Money\n * Account deposit, uses direct mUSD params (asset, wallet, recipient).\n * Otherwise, uses the standard ETH flow.\n *\n * @param request - Strategy quotes request.\n * @returns A single combined fiat strategy quote, or an empty array when inputs/quotes are unavailable.\n */\nexport async function getFiatQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const { messenger, transaction } = request;\n\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transaction.id];\n const amountFiat = transactionData?.fiatPayment?.amountFiat;\n const requiredTokens = transactionData?.tokens ?? [];\n\n if (\n !amountFiat ||\n !request.fiatPaymentMethod ||\n requiredTokens.length !== 1\n ) {\n return [];\n }\n\n const useDirectMusd =\n getDirectMoneyMusdEnabled(messenger) &&\n isMoneyAccountDepositTransaction(transaction);\n\n if (useDirectMusd) {\n const requiredToken = requiredTokens[0];\n\n const directQuote = await getDirectMusdFiatQuote({\n amountFiat,\n fiatPaymentMethod: request.fiatPaymentMethod,\n messenger,\n moneyAccountAddress: transaction.txParams.from as Hex,\n requiredToken,\n transactionId: transaction.id,\n });\n\n return directQuote ? [directQuote] : [];\n }\n\n return executeFiatQuotePipeline(request, {\n amountFiat,\n fiatAsset: deriveFiatAssetForFiatPayment(transaction, messenger),\n fiatPaymentMethod: request.fiatPaymentMethod,\n rampsWalletAddress: request.from,\n requiredTokens,\n });\n}\n\nasync function executeFiatQuotePipeline(\n request: PayStrategyGetQuotesRequest,\n options: FiatQuotePipelineOptions,\n): Promise<TransactionPayQuote<FiatQuote>[]> {\n const {\n accountSupports7702,\n from: walletAddress,\n messenger,\n transaction,\n } = request;\n const {\n amountFiat,\n fiatAsset,\n fiatPaymentMethod,\n rampsWalletAddress,\n requiredTokens,\n } = options;\n const transactionId = transaction.id;\n\n try {\n const requiredToken = requiredTokens[0];\n\n const relayRequest = buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n });\n\n if (!relayRequest) {\n throw new Error('Failed to build relay request from fiat amount');\n }\n\n const relayQuotes = await getRelayQuotes({\n accountSupports7702,\n from: walletAddress,\n messenger,\n requests: [relayRequest],\n transaction,\n });\n\n const relayQuote = relayQuotes[0];\n if (!relayQuote) {\n throw new Error('No relay quote available for fiat estimation');\n }\n\n const isSourceNative =\n fiatAsset.address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();\n const gasDeductedFromSource =\n isSourceNative || relayQuote.fees.isSourceGasFeeToken === true;\n\n const relayTotalFeeUsd = gasDeductedFromSource\n ? getRelayTotalFeeUsd(relayQuote)\n : getNonGasRelayFeeUsd(relayQuote);\n const adjustedAmountFiat = new BigNumber(amountFiat).plus(relayTotalFeeUsd);\n\n if (\n !adjustedAmountFiat.isFinite() ||\n !adjustedAmountFiat.gt(0) ||\n !relayTotalFeeUsd.isFinite() ||\n !relayTotalFeeUsd.gte(0)\n ) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n const adjustedAmount = adjustedAmountFiat.toNumber();\n\n if (!Number.isFinite(adjustedAmount) || adjustedAmount <= 0) {\n throw new Error('Invalid fiat amount after relay fee adjustment');\n }\n\n log('Fiat quote flow', {\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n rampsWalletAddress,\n relayTotalFeeUsd: relayTotalFeeUsd.toString(10),\n sourceAmountRaw: relayRequest.sourceTokenAmount,\n transactionId,\n });\n\n const fiatQuote = await getRampsQuote({\n adjustedAmount,\n fiatAsset,\n fiatPaymentMethod,\n messenger,\n walletAddress: rampsWalletAddress,\n });\n\n // When Transak Native is the resolved provider, prefer its own quote's fee\n // so the estimate matches what Transak Native will charge. The relay path\n // stays fee-on-top, so request the native quote in the same mode.\n const nativeRampsFee = await getNativeTransakRampsFee({\n adjustedAmount,\n fiatAsset,\n fiatPaymentMethod,\n fiatQuote,\n isFeeExcludedFromFiat: true,\n messenger,\n });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment: TransactionFiatPayment) => {\n fiatPayment.rampsQuote = fiatQuote;\n fiatPayment.caipAssetId = buildCaipAssetType(\n fiatAsset.chainId,\n fiatAsset.address,\n );\n },\n transactionId,\n });\n\n return [\n combineQuotes({\n adjustedAmountFiat: adjustedAmountFiat.toString(10),\n amountFiat,\n fiatQuote,\n nativeRampsFee,\n relayQuote,\n }),\n ];\n } catch (error) {\n log('Failed to fetch fiat quotes', { error, transactionId });\n\n messenger.call('TransactionPayController:updateFiatPayment', {\n callback: (fiatPayment) => {\n fiatPayment.rampsQuote = undefined;\n },\n transactionId,\n });\n }\n\n return [];\n}\n\nfunction buildRelayRequestFromAmountFiat({\n amountFiat,\n fiatAsset,\n messenger,\n requiredToken,\n walletAddress,\n}: {\n amountFiat: string;\n fiatAsset: {\n address: Hex;\n chainId: Hex;\n };\n messenger: PayStrategyGetQuotesRequest['messenger'];\n requiredToken: TransactionPayRequiredToken;\n walletAddress: Hex;\n}): QuoteRequest | undefined {\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!sourceFiatRate) {\n return undefined;\n }\n\n const tokenInfo = getTokenInfo(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!tokenInfo) {\n return undefined;\n }\n\n const sourceAmountRaw = computeRawFromFiatAmount(\n amountFiat,\n tokenInfo.decimals,\n sourceFiatRate.usdRate,\n );\n\n if (!sourceAmountRaw) {\n return undefined;\n }\n\n return {\n from: walletAddress,\n // Force EXACT_INPUT mode: source amount is pre-calculated from the fiat\n // amount, so the relay should treat it as a fixed input rather than\n // computing it from the target.\n isPostQuote: true,\n sourceBalanceRaw: sourceAmountRaw,\n sourceChainId: fiatAsset.chainId,\n sourceTokenAddress: fiatAsset.address,\n sourceTokenAmount: sourceAmountRaw,\n targetAmountMinimum: requiredToken.amountRaw,\n targetChainId: requiredToken.chainId,\n targetTokenAddress: requiredToken.address,\n };\n}\n\n/**\n * Combines fiat and relay legs into a single MM Pay fiat strategy quote.\n *\n * @param params - Combined quote inputs.\n * @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.\n * @param params.amountFiat - User-entered fiat amount.\n * @param params.fiatQuote - Selected ramps quote.\n * @param params.nativeRampsFee - Native Transak fee to use in place of the aggregator ramps fee, or null.\n * @param params.relayQuote - Estimated relay quote.\n * @returns A single fiat strategy quote with split fee buckets.\n * @remarks\n * Fee mapping contract for MM Pay Fiat strategy:\n * - `fees.provider`: Total provider fee (relay provider/swap fee + ramps provider/network fee).\n * Consumed by UI transaction fee row and tooltip provider fee.\n * - `fees.providerFiat`: Fiat on-ramp provider fees only (`providerFee + networkFee` from ramps quote).\n * Optional breakdown; client can derive relay portion via `provider - providerFiat`.\n * - `fees.sourceNetwork` / `fees.targetNetwork`: Relay settlement network fees.\n * Consumed by UI transaction fee row and tooltip network fee.\n * - `fees.metaMask`: MM Pay fee (currently 100 bps over `amountFiat + adjustedAmountFiat`).\n * Consumed by UI transaction fee row and tooltip MetaMask fee.\n * - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.\n */\nfunction combineQuotes({\n adjustedAmountFiat,\n amountFiat,\n fiatQuote,\n nativeRampsFee,\n relayQuote,\n}: {\n adjustedAmountFiat: string;\n amountFiat: string;\n fiatQuote: RampsQuote;\n nativeRampsFee: BigNumber | null;\n relayQuote: TransactionPayQuote<RelayQuote>;\n}): TransactionPayQuote<FiatQuote> {\n const rampsProviderFee = nativeRampsFee ?? getRampsProviderFee(fiatQuote);\n const totalProviderFee = new BigNumber(relayQuote.fees.provider.usd)\n .plus(rampsProviderFee)\n .toString(10);\n const rampsProviderFeeStr = rampsProviderFee.toString(10);\n const metaMaskFee = getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n }).toString(10);\n\n return {\n ...relayQuote,\n fees: {\n ...relayQuote.fees,\n metaMask: {\n fiat: metaMaskFee,\n usd: metaMaskFee,\n },\n provider: {\n fiat: totalProviderFee,\n usd: totalProviderFee,\n },\n providerFiat: {\n fiat: rampsProviderFeeStr,\n usd: rampsProviderFeeStr,\n },\n },\n original: {\n rampsQuote: fiatQuote,\n relayQuote: relayQuote.original,\n },\n strategy: TransactionPayStrategy.Fiat,\n };\n}\n\n/**\n * Ramps providers handle network gas fees themselves but report them separately\n * as `networkFee` alongside their `providerFee`. We combine both into a single\n * ramps provider fee for the `providerFiat` breakdown.\n *\n * @param fiatQuote - The ramps quote containing provider and network fees.\n * @returns Combined ramps provider fee as a BigNumber.\n */\nfunction getRampsProviderFee(fiatQuote: RampsQuote): BigNumber {\n return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(\n fiatQuote.quote.networkFee ?? 0,\n );\n}\n\nfunction getRelayTotalFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.sourceNetwork.estimate.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getNonGasRelayFeeUsd(\n relayQuote: TransactionPayQuote<RelayQuote>,\n): BigNumber {\n return new BigNumber(relayQuote.fees.provider.usd)\n .plus(relayQuote.fees.targetNetwork.usd)\n .plus(relayQuote.fees.metaMask.usd);\n}\n\nfunction getMetaMaskFee({\n adjustedAmountFiat,\n amountFiat,\n}: {\n adjustedAmountFiat: BigNumber.Value;\n amountFiat: BigNumber.Value;\n}): BigNumber {\n return new BigNumber(amountFiat).plus(adjustedAmountFiat).dividedBy(100);\n}\n"]}