@metamask-previews/transaction-pay-controller 28.0.2-preview-0a8ce9948 → 28.0.2-preview-95a403d7b

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,8 +9,15 @@ 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))
13
+ - The fee is read via the stateless `TransakService:getBuyQuote` action so the estimate does not write the shared native buy-quote state used by Unified Buy; clients must delegate `TransakService:getBuyQuote` to the `TransactionPayController` messenger.
14
+ - Charge direct Monad mUSD on-ramp fees on top of the entered amount (fee-on-top), so the total is the entered amount plus fees ([#9317](https://github.com/MetaMask/core/pull/9317))
12
15
  - Bump `@metamask/utils` from `^11.12.0` to `^12.0.0` ([#10192](https://github.com/MetaMask/core/pull/10192))
13
16
 
17
+ ### Fixed
18
+
19
+ - Detect nested `perpsDepositAndOrder` and `predictDepositAndOrder` transactions when selecting `EXACT_OUTPUT` Relay quotes ([#10222](https://github.com/MetaMask/core/pull/10222))
20
+
14
21
  ## [28.0.2]
15
22
 
16
23
  ### Fixed
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-direct-musd.d.ts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EACX,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAM3C,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE3B,2BAA2B,EAC3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;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.ts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-direct-musd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EACX,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAM3C,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE3B,2BAA2B,EAC3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;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,CA2DtD;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.js';
7
7
  import { submitMoneyAccountVaultDeposit } from '../../utils/ma-vault-deposit.js';
8
8
  import { buildCaipAssetType, getTokenInfo } from '../../utils/token.js';
9
9
  import { MUSD_MONAD_FIAT_ASSET } from './constants.js';
10
- import { getRampsQuote, getRawSourceAmountFromOrderCryptoAmount, resolveSourceAmountRaw, validateOrderAsset, } from './utils.js';
10
+ import { getNativeTransakRampsFee, getRampsQuote, getRawSourceAmountFromOrderCryptoAmount, resolveSourceAmountRaw, validateOrderAsset, } from './utils.js';
11
11
  const log = createModuleLogger(projectLogger, 'fiat-direct-musd');
12
12
  const DIRECT_MUSD_ERROR_PREFIX = 'Direct mUSD: ';
13
13
  /**
@@ -36,6 +36,18 @@ 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 is
41
+ // fee-on-top (the fee is added to the entered amount), so request the native
42
+ // quote in that mode.
43
+ const nativeRampsFee = await getNativeTransakRampsFee({
44
+ adjustedAmount,
45
+ fiatAsset: MUSD_MONAD_FIAT_ASSET,
46
+ fiatPaymentMethod,
47
+ fiatQuote,
48
+ isFeeExcludedFromFiat: true,
49
+ messenger,
50
+ });
39
51
  messenger.call('TransactionPayController:updateFiatPayment', {
40
52
  callback: (fiatPayment) => {
41
53
  fiatPayment.rampsQuote = fiatQuote;
@@ -53,6 +65,7 @@ export async function getDirectMusdFiatQuote({ amountFiat, fiatPaymentMethod, me
53
65
  fiatQuote,
54
66
  messenger,
55
67
  moneyAccountAddress,
68
+ nativeRampsFee,
56
69
  requiredToken,
57
70
  });
58
71
  }
@@ -104,7 +117,7 @@ export async function submitDirectMusdAfterFiatCompletion({ order, request, }) {
104
117
  throw prefixError(error, DIRECT_MUSD_ERROR_PREFIX);
105
118
  }
106
119
  }
107
- function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAccountAddress, requiredToken, }) {
120
+ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAccountAddress, nativeRampsFee, requiredToken, }) {
108
121
  const tokenInfo = getTokenInfo(messenger, MUSD_MONAD_FIAT_ASSET.address, MUSD_MONAD_FIAT_ASSET.chainId);
109
122
  if (!tokenInfo) {
110
123
  throw new Error('Unable to resolve mUSD token info for direct fiat quote');
@@ -113,20 +126,45 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
113
126
  cryptoAmount: fiatQuote.quote.amountOut,
114
127
  decimals: tokenInfo.decimals,
115
128
  });
116
- const rampsProviderFee = getRampsProviderFee(fiatQuote).toString(10);
129
+ // Transak Native returns a single total fee, so the aggregator's separate
130
+ // provider/network split collapses: the whole native fee sits in the provider
131
+ // bucket and the source-network fee is zero. The `providerFiat` total stays
132
+ // correct either way.
133
+ const rampsProviderFee = (nativeRampsFee ?? getSafeFee(fiatQuote.quote.providerFee)).toString(10);
134
+ const rampsNetworkFee = nativeRampsFee
135
+ ? '0'
136
+ : getSafeFee(fiatQuote.quote.networkFee).toString(10);
137
+ const rampsTotalFee = new BigNumber(rampsProviderFee)
138
+ .plus(rampsNetworkFee)
139
+ .toString(10);
140
+ const targetAmountFiat = getDirectMusdTargetAmountFiat(fiatQuote);
117
141
  const sourceAmountHuman = new BigNumber(sourceAmountRaw)
118
142
  .shiftedBy(-tokenInfo.decimals)
119
143
  .toString(10);
120
144
  return {
145
+ // Direct mUSD is fee-on-top: the fee is added to the entered amount, so the
146
+ // fees are NOT already inside the source amount and the total becomes
147
+ // amount + fees (see calculateTotals).
148
+ areFeesIncludedInSourceAmount: false,
121
149
  dust: { fiat: '0', usd: '0' },
122
150
  estimatedDuration: 0,
123
151
  fees: {
124
152
  metaMask: { fiat: '0', usd: '0' },
125
153
  provider: { fiat: rampsProviderFee, usd: rampsProviderFee },
126
- providerFiat: { fiat: rampsProviderFee, usd: rampsProviderFee },
154
+ providerFiat: { fiat: rampsTotalFee, usd: rampsTotalFee },
127
155
  sourceNetwork: {
128
- estimate: { fiat: '0', human: '0', raw: '0', usd: '0' },
129
- max: { fiat: '0', human: '0', raw: '0', usd: '0' },
156
+ estimate: {
157
+ fiat: rampsNetworkFee,
158
+ human: '0',
159
+ raw: '0',
160
+ usd: rampsNetworkFee,
161
+ },
162
+ max: {
163
+ fiat: rampsNetworkFee,
164
+ human: '0',
165
+ raw: '0',
166
+ usd: rampsNetworkFee,
167
+ },
130
168
  },
131
169
  targetNetwork: { fiat: '0', usd: '0' },
132
170
  },
@@ -153,10 +191,20 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
153
191
  usd: amountFiat,
154
192
  },
155
193
  strategy: TransactionPayStrategy.Fiat,
156
- targetAmount: { fiat: amountFiat, usd: amountFiat },
194
+ targetAmount: { fiat: targetAmountFiat, usd: targetAmountFiat },
157
195
  };
158
196
  }
159
- function getRampsProviderFee(fiatQuote) {
160
- return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(fiatQuote.quote.networkFee ?? 0);
197
+ function getDirectMusdTargetAmountFiat(fiatQuote) {
198
+ const amountOutInFiat = new BigNumber(fiatQuote.quote.amountOutInFiat ?? NaN);
199
+ if (amountOutInFiat.isFinite() && amountOutInFiat.isGreaterThanOrEqualTo(0)) {
200
+ return amountOutInFiat.toString(10);
201
+ }
202
+ return new BigNumber(fiatQuote.quote.amountOut).toString(10);
203
+ }
204
+ function getSafeFee(value) {
205
+ const fee = new BigNumber(value ?? 0);
206
+ return fee.isFinite() && fee.isGreaterThanOrEqualTo(0)
207
+ ? fee
208
+ : new BigNumber(0);
161
209
  }
162
210
  //# sourceMappingURL=fiat-direct-musd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-direct-musd.js","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 = getRampsProviderFee(fiatQuote).toString(10);\n const sourceAmountHuman = new BigNumber(sourceAmountRaw)\n .shiftedBy(-tokenInfo.decimals)\n .toString(10);\n\n return {\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: rampsProviderFee, usd: rampsProviderFee },\n sourceNetwork: {\n estimate: { fiat: '0', human: '0', raw: '0', usd: '0' },\n max: { fiat: '0', human: '0', raw: '0', usd: '0' },\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: amountFiat, usd: amountFiat },\n };\n}\n\nfunction getRampsProviderFee(fiatQuote: RampsQuote): BigNumber {\n return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(\n fiatQuote.quote.networkFee ?? 0,\n );\n}\n"]}
1
+ {"version":3,"file":"fiat-direct-musd.js","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 is\n // fee-on-top (the fee is added to the entered amount), so request the native\n // quote in that mode.\n const nativeRampsFee = await getNativeTransakRampsFee({\n adjustedAmount,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\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 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 // Direct mUSD is fee-on-top: the fee is added to the entered amount, so the\n // fees are NOT already inside the source amount and the total becomes\n // amount + fees (see calculateTotals).\n areFeesIncludedInSourceAmount: false,\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-quotes.d.ts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAYxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;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.ts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-quotes.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAYxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;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.js';
6
6
  import { buildCaipAssetType, computeRawFromFiatAmount, getTokenFiatRate, getTokenInfo, } from '../../utils/token.js';
7
7
  import { getRelayQuotes } from '../relay/relay-quotes.js';
8
8
  import { getDirectMusdFiatQuote } from './fiat-direct-musd.js';
9
- import { deriveFiatAssetForFiatPayment, getRampsQuote, isMoneyAccountDepositTransaction, } from './utils.js';
9
+ import { deriveFiatAssetForFiatPayment, getNativeTransakRampsFee, getRampsQuote, isMoneyAccountDepositTransaction, } from './utils.js';
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.js","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.js","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"]}
@@ -2,6 +2,7 @@ import type { Quote as RampsQuote, RampsOrder, RampsOrderCryptoCurrency } from '
2
2
  import type { TransactionMeta } from '@metamask/transaction-controller';
3
3
  import { TransactionType } from '@metamask/transaction-controller';
4
4
  import type { Hex } from '@metamask/utils';
5
+ import { BigNumber } from 'bignumber.js';
5
6
  import type { TransactionPayControllerMessenger } from '../../types.js';
6
7
  import type { RelayQuote } from '../relay/types.js';
7
8
  import type { TransactionPayFiatAsset } from './constants.js';
@@ -145,4 +146,34 @@ export declare function validateRelayRateDrift({ originalQuote, discoveryQuote,
145
146
  * @returns The provider code, or `null` if the format is invalid.
146
147
  */
147
148
  export declare function extractProviderCode(provider: string | undefined): string | null;
149
+ /**
150
+ * When the resolved ramps provider is Transak Native, fetches the native
151
+ * Transak buy quote and returns its total fee so the estimate matches what
152
+ * Transak Native actually charges.
153
+ *
154
+ * The native lookup (`/api/v2/lookup/quotes`) is an unauthenticated, API-key
155
+ * only call, so it is safe to run at estimate time before the user signs in to
156
+ * Transak. Returns `null` when the provider is not Transak Native, or when the
157
+ * native lookup fails or returns an unusable fee, so the caller falls back to
158
+ * the aggregator quote's fee.
159
+ *
160
+ * @param options - Native fee options.
161
+ * @param options.adjustedAmount - Fiat amount (USD) sent to ramps.
162
+ * @param options.fiatAsset - Fiat asset being bought.
163
+ * @param options.fiatPaymentMethod - Selected fiat payment method.
164
+ * @param options.fiatQuote - The resolved aggregator quote (used to detect native).
165
+ * @param options.isFeeExcludedFromFiat - Whether Transak adds its fee on top of
166
+ * the fiat amount (`true`) or carves it out of the amount (`false`). Must mirror
167
+ * the eventual checkout mode so the estimate equals the charge.
168
+ * @param options.messenger - Controller messenger.
169
+ * @returns The native total fee as a BigNumber, or `null` to use the aggregator fee.
170
+ */
171
+ export declare function getNativeTransakRampsFee({ adjustedAmount, fiatAsset, fiatPaymentMethod, fiatQuote, isFeeExcludedFromFiat, messenger, }: {
172
+ adjustedAmount: number;
173
+ fiatAsset: TransactionPayFiatAsset;
174
+ fiatPaymentMethod: string;
175
+ fiatQuote: RampsQuote;
176
+ isFeeExcludedFromFiat: boolean;
177
+ messenger: TransactionPayControllerMessenger;
178
+ }): Promise<BigNumber | null>;
148
179
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"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"}
@@ -234,4 +234,57 @@ export function extractProviderCode(provider) {
234
234
  }
235
235
  return parts.length === 1 ? parts[0] : null;
236
236
  }
237
+ /**
238
+ * Provider codes that identify Transak's native (non-aggregator) integration.
239
+ * Matches the codes emitted by `TransakService` for production and staging.
240
+ */
241
+ const NATIVE_TRANSAK_PROVIDER_CODES = [
242
+ 'transak-native',
243
+ 'transak-native-staging',
244
+ ];
245
+ /**
246
+ * When the resolved ramps provider is Transak Native, fetches the native
247
+ * Transak buy quote and returns its total fee so the estimate matches what
248
+ * Transak Native actually charges.
249
+ *
250
+ * The native lookup (`/api/v2/lookup/quotes`) is an unauthenticated, API-key
251
+ * only call, so it is safe to run at estimate time before the user signs in to
252
+ * Transak. Returns `null` when the provider is not Transak Native, or when the
253
+ * native lookup fails or returns an unusable fee, so the caller falls back to
254
+ * the aggregator quote's fee.
255
+ *
256
+ * @param options - Native fee options.
257
+ * @param options.adjustedAmount - Fiat amount (USD) sent to ramps.
258
+ * @param options.fiatAsset - Fiat asset being bought.
259
+ * @param options.fiatPaymentMethod - Selected fiat payment method.
260
+ * @param options.fiatQuote - The resolved aggregator quote (used to detect native).
261
+ * @param options.isFeeExcludedFromFiat - Whether Transak adds its fee on top of
262
+ * the fiat amount (`true`) or carves it out of the amount (`false`). Must mirror
263
+ * the eventual checkout mode so the estimate equals the charge.
264
+ * @param options.messenger - Controller messenger.
265
+ * @returns The native total fee as a BigNumber, or `null` to use the aggregator fee.
266
+ */
267
+ export async function getNativeTransakRampsFee({ adjustedAmount, fiatAsset, fiatPaymentMethod, fiatQuote, isFeeExcludedFromFiat, messenger, }) {
268
+ const providerCode = extractProviderCode(fiatQuote.provider);
269
+ if (!providerCode || !NATIVE_TRANSAK_PROVIDER_CODES.includes(providerCode)) {
270
+ return null;
271
+ }
272
+ try {
273
+ const assetId = buildCaipAssetType(fiatAsset.chainId, fiatAsset.address);
274
+ const network = assetId.split('/')[0];
275
+ const nativeQuote = await messenger.call('TransakService:getBuyQuote', DEFAULT_FIAT_CURRENCY, assetId, network, fiatPaymentMethod, String(adjustedAmount), isFeeExcludedFromFiat);
276
+ const fee = new BigNumber(nativeQuote.totalFee ?? NaN);
277
+ if (!fee.isFinite() || fee.isLessThan(0)) {
278
+ log('Native Transak quote returned an unusable fee; using aggregator fee', {
279
+ totalFee: nativeQuote.totalFee,
280
+ });
281
+ return null;
282
+ }
283
+ return fee;
284
+ }
285
+ catch (error) {
286
+ log('Native Transak fee fetch failed; using aggregator fee', { error });
287
+ return null;
288
+ }
289
+ }
237
290
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Quote as RampsQuote,\n RampsOrder,\n RampsOrderCryptoCurrency,\n} from '@metamask/ramps-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { TransactionType } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger.js';\nimport type { TransactionPayControllerMessenger } from '../../types.js';\nimport {\n getFiatAssetPerTransactionType,\n getFiatEnabledTypes,\n} from '../../utils/feature-flags.js';\nimport { buildCaipAssetType, getTokenInfo } from '../../utils/token.js';\nimport { getTransferredAmountFromTxHash } from '../../utils/transaction.js';\nimport type { RelayQuote } from '../relay/types.js';\nimport type { TransactionPayFiatAsset } from './constants.js';\nimport { DEFAULT_FIAT_CURRENCY, FIAT_ENABLED_TYPES } from './constants.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-utils');\n\nexport function deriveFiatAssetForFiatPayment(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayFiatAsset {\n const enabledTypes = getFiatEnabledTypes(messenger);\n const txType = resolveTransactionType(transaction, enabledTypes);\n\n return getFiatAssetPerTransactionType(messenger, txType);\n}\n\n/**\n * Resolves the effective transaction type for fiat strategy purposes.\n *\n * For non-batch transactions returns the transaction's own type.\n * For batch transactions returns the first nested transaction type\n * that appears in the enabled types list, or the batch type itself\n * if no nested type matches.\n *\n * @param transaction - The transaction metadata to inspect.\n * @param enabledTypes - Transaction types eligible for fiat payment.\n * @returns The resolved transaction type, or `undefined`.\n */\nexport function resolveTransactionType(\n transaction: TransactionMeta,\n enabledTypes: TransactionType[],\n): TransactionType | undefined {\n if (transaction.type !== TransactionType.batch) {\n return transaction.type;\n }\n\n const nestedType = transaction.nestedTransactions?.find(\n (tx) => tx.type && enabledTypes.includes(tx.type),\n )?.type;\n\n return nestedType ?? transaction.type;\n}\n\n/**\n * Checks whether a transaction is a Money Account deposit.\n *\n * Handles both direct `moneyAccountDeposit` transactions and EIP-7702\n * batch transactions that contain a `moneyAccountDeposit` nested call.\n * Uses {@link resolveTransactionType} with `FIAT_ENABLED_TYPES` to\n * correctly skip non-deposit nested types (e.g. `tokenMethodApprove`).\n *\n * @param transaction - The transaction metadata to inspect.\n * @returns `true` if the transaction is a Money Account deposit.\n */\nexport function isMoneyAccountDepositTransaction(\n transaction: TransactionMeta,\n): boolean {\n return (\n resolveTransactionType(transaction, FIAT_ENABLED_TYPES) ===\n TransactionType.moneyAccountDeposit\n );\n}\n\n/**\n * Fetches the first matching Ramps quote for a fiat asset and payment method.\n *\n * @param options - Quote options.\n * @param options.adjustedAmount - Fiat amount sent to Ramps.\n * @param options.errorMessage - Error thrown when no matching quote is returned.\n * @param options.fiatAsset - Fiat asset to buy.\n * @param options.fiatPaymentMethod - Selected fiat payment method.\n * @param options.messenger - Controller messenger.\n * @param options.walletAddress - Wallet address that receives the on-ramped asset.\n * @returns The first matching Ramps quote.\n */\nexport async function getRampsQuote({\n adjustedAmount,\n errorMessage = 'No matching ramps quote found for selected provider',\n fiatAsset,\n fiatPaymentMethod,\n messenger,\n walletAddress,\n}: {\n adjustedAmount: number;\n errorMessage?: string;\n fiatAsset: TransactionPayFiatAsset;\n fiatPaymentMethod: string;\n messenger: TransactionPayControllerMessenger;\n walletAddress: string;\n}): Promise<RampsQuote> {\n const quotes = await messenger.call('RampsController:getQuotes', {\n amount: adjustedAmount,\n assetId: buildCaipAssetType(fiatAsset.chainId, fiatAsset.address),\n autoSelectProvider: true,\n fiat: DEFAULT_FIAT_CURRENCY,\n paymentMethods: [fiatPaymentMethod],\n restrictToKnownOrNativeProviders: true,\n walletAddress,\n });\n\n log('Fetched ramps quotes', {\n quotesCount: quotes.success?.length ?? 0,\n });\n\n const quote = quotes.success?.[0];\n\n if (!quote) {\n throw new Error(errorMessage);\n }\n\n return quote;\n}\n\n/**\n * Validates that a completed order's crypto asset matches the expected fiat asset.\n *\n * @param options - The validation options.\n * @param options.expectedAsset - The expected fiat asset derived from the transaction type.\n * @param options.orderCrypto - The crypto currency information from the completed order.\n * @param options.transactionId - Transaction ID for error reporting.\n */\nexport function validateOrderAsset({\n expectedAsset,\n orderCrypto,\n transactionId,\n}: {\n expectedAsset: TransactionPayFiatAsset;\n orderCrypto: RampsOrderCryptoCurrency | undefined;\n transactionId: string;\n}): void {\n const orderAssetId = orderCrypto?.assetId?.toLowerCase();\n const expectedAssetId = buildCaipAssetType(\n expectedAsset.chainId,\n expectedAsset.address,\n ).toLowerCase();\n const expectedChainId = expectedAssetId.split('/')[0];\n const orderChainId = orderCrypto?.chainId?.toLowerCase();\n\n if (orderAssetId && orderAssetId !== expectedAssetId) {\n throw new Error(\n `Order asset mismatch for transaction ${transactionId}: ` +\n `expected ${expectedAssetId}, got ${orderAssetId}`,\n );\n }\n\n if (orderChainId && orderChainId !== expectedChainId) {\n throw new Error(\n `Order chain mismatch for transaction ${transactionId}: ` +\n `expected ${expectedChainId}, got ${orderChainId}`,\n );\n }\n}\n\n/**\n * Result from {@link resolveSourceAmountRaw}.\n */\nexport type ResolvedSourceAmount = {\n /** Raw (atomic) source amount as a decimal string. */\n amountRaw: string;\n /**\n * Block number of the ramps settlement transaction as a 0x-prefixed hex\n * string. Populated when `order.txHash` is present and the on-chain receipt\n * was successfully fetched (ERC-20 only). Use this as the `fromBlock` for\n * CHOMP idempotency log queries — it reuses the receipt already fetched for\n * the amount and requires no additional network request.\n */\n fromBlock: Hex | undefined;\n};\n\n/**\n * Resolves the raw source amount for a completed fiat order.\n *\n * Attempts to read the actual transferred amount from the on-chain transaction\n * identified by `order.txHash`. If the on-chain read fails or returns\n * no amount, falls back to computing the amount from `order.cryptoAmount`.\n *\n * Also returns the receipt `blockNumber` from the ramps tx when available, so\n * callers can use it as a CHOMP idempotency baseline without any extra request.\n *\n * @param options - The resolution options.\n * @param options.messenger - Controller messenger for network access.\n * @param options.order - The completed on-ramp order.\n * @param options.fiatAsset - The fiat asset describing the expected token.\n * @param options.walletAddress - Recipient wallet address for on-chain lookup.\n * @returns The raw (atomic) source amount and optional receipt block number.\n */\nexport async function resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress,\n}: {\n messenger: TransactionPayControllerMessenger;\n order: RampsOrder;\n fiatAsset: TransactionPayFiatAsset;\n walletAddress: Hex;\n}): Promise<ResolvedSourceAmount> {\n if (order.txHash) {\n try {\n const { amountRaw: onChainAmount, blockNumber } =\n await getTransferredAmountFromTxHash({\n messenger,\n txHash: order.txHash,\n chainId: fiatAsset.chainId,\n tokenAddress: fiatAsset.address,\n walletAddress,\n });\n\n if (onChainAmount) {\n log('Resolved source amount from on-chain transaction', {\n txHash: order.txHash,\n onChainAmount,\n blockNumber,\n });\n return { amountRaw: onChainAmount, fromBlock: blockNumber };\n }\n } catch (error) {\n log(\n 'Failed to read on-chain amount, falling back to order.cryptoAmount',\n { txHash: order.txHash, error },\n );\n }\n }\n\n const tokenInfo = getTokenInfo(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!tokenInfo) {\n throw new Error(\n `Unable to resolve token info for fiat asset ${fiatAsset.address} on chain ${fiatAsset.chainId}`,\n );\n }\n\n const amountRaw = getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount: order.cryptoAmount,\n decimals: tokenInfo.decimals,\n });\n\n return { amountRaw, fromBlock: undefined };\n}\n\n/**\n * Converts the order's human-readable crypto amount to a raw token amount.\n *\n * @param options - The conversion options.\n * @param options.cryptoAmount - Human-readable crypto amount from the completed order.\n * @param options.decimals - Token decimals for the fiat asset.\n * @returns The raw token amount as a string.\n */\nexport function getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount,\n decimals,\n}: {\n cryptoAmount: RampsOrder['cryptoAmount'];\n decimals: number;\n}): string {\n const normalizedAmount = new BigNumber(String(cryptoAmount));\n\n if (!normalizedAmount.isFinite() || normalizedAmount.lte(0)) {\n throw new Error(\n `Invalid fiat order crypto amount: ${String(cryptoAmount)}`,\n );\n }\n\n const rawAmount = normalizedAmount\n .shiftedBy(decimals)\n .decimalPlaces(0, BigNumber.ROUND_DOWN)\n .toFixed(0);\n\n if (!new BigNumber(rawAmount).gt(0)) {\n throw new Error('Computed fiat order source amount is not positive');\n }\n\n return rawAmount;\n}\n\n/**\n * Validates that the relay exchange rate hasn't drifted significantly between\n * the original quoting phase and the post-settlement discovery quote.\n *\n * Compares the USD output/input ratio from both quotes. This normalises for\n * different source amounts (quoting phase uses a theoretical amount, discovery\n * uses the actual settled amount) so the comparison reflects genuine rate\n * movement rather than amount differences.\n *\n * @param options - The validation options.\n * @param options.originalQuote - Relay quote from the original quoting phase.\n * @param options.discoveryQuote - Relay quote from the post-settlement discovery.\n * @param options.maxRateDriftPercent - Maximum allowed rate drift percentage.\n * @param options.transactionId - Transaction ID for error reporting.\n */\nexport function validateRelayRateDrift({\n originalQuote,\n discoveryQuote,\n maxRateDriftPercent,\n transactionId,\n}: {\n originalQuote: RelayQuote;\n discoveryQuote: RelayQuote;\n maxRateDriftPercent: number;\n transactionId: string;\n}): void {\n const originalIn = new BigNumber(originalQuote.details.currencyIn.amountUsd);\n const originalOut = new BigNumber(\n originalQuote.details.currencyOut.amountUsd,\n );\n const discoveryIn = new BigNumber(\n discoveryQuote.details.currencyIn.amountUsd,\n );\n const discoveryOut = new BigNumber(\n discoveryQuote.details.currencyOut.amountUsd,\n );\n\n if (\n !originalIn.gt(0) ||\n !originalOut.gt(0) ||\n !discoveryIn.gt(0) ||\n !discoveryOut.gt(0)\n ) {\n return;\n }\n\n const originalRate = originalOut.dividedBy(originalIn);\n const discoveryRate = discoveryOut.dividedBy(discoveryIn);\n\n const driftPercent = originalRate\n .minus(discoveryRate)\n .dividedBy(originalRate)\n .multipliedBy(100);\n\n log('Relay rate drift check', {\n originalRate: originalRate.toFixed(6),\n discoveryRate: discoveryRate.toFixed(6),\n driftPercent: driftPercent.toFixed(2),\n maxRateDriftPercent,\n transactionId,\n });\n\n if (driftPercent.gt(maxRateDriftPercent)) {\n throw new Error(\n `Relay rate drift too high for transaction ` +\n `${driftPercent.toFixed(2)}% exceeds ${maxRateDriftPercent}% max`,\n );\n }\n}\n\n/**\n * Extracts the provider code from a ramps provider string.\n *\n * Accepts the canonical provider code (e.g. `transak-native`) and, for\n * backwards compatibility, the legacy path form (e.g. `/providers/transak-native`).\n *\n * @param provider - Canonical provider code, or legacy provider path.\n * @returns The provider code, or `null` if the format is invalid.\n */\nexport function extractProviderCode(\n provider: string | undefined,\n): string | null {\n if (!provider) {\n return null;\n }\n\n const parts = provider.split('/').filter(Boolean);\n\n if (parts[0] === 'providers') {\n return parts[1] ?? null;\n }\n\n return parts.length === 1 ? parts[0] : null;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Quote as RampsQuote,\n RampsOrder,\n RampsOrderCryptoCurrency,\n} from '@metamask/ramps-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { TransactionType } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger.js';\nimport type { TransactionPayControllerMessenger } from '../../types.js';\nimport {\n getFiatAssetPerTransactionType,\n getFiatEnabledTypes,\n} from '../../utils/feature-flags.js';\nimport { buildCaipAssetType, getTokenInfo } from '../../utils/token.js';\nimport { getTransferredAmountFromTxHash } from '../../utils/transaction.js';\nimport type { RelayQuote } from '../relay/types.js';\nimport type { TransactionPayFiatAsset } from './constants.js';\nimport { DEFAULT_FIAT_CURRENCY, FIAT_ENABLED_TYPES } from './constants.js';\n\nconst log = createModuleLogger(projectLogger, 'fiat-utils');\n\nexport function deriveFiatAssetForFiatPayment(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayFiatAsset {\n const enabledTypes = getFiatEnabledTypes(messenger);\n const txType = resolveTransactionType(transaction, enabledTypes);\n\n return getFiatAssetPerTransactionType(messenger, txType);\n}\n\n/**\n * Resolves the effective transaction type for fiat strategy purposes.\n *\n * For non-batch transactions returns the transaction's own type.\n * For batch transactions returns the first nested transaction type\n * that appears in the enabled types list, or the batch type itself\n * if no nested type matches.\n *\n * @param transaction - The transaction metadata to inspect.\n * @param enabledTypes - Transaction types eligible for fiat payment.\n * @returns The resolved transaction type, or `undefined`.\n */\nexport function resolveTransactionType(\n transaction: TransactionMeta,\n enabledTypes: TransactionType[],\n): TransactionType | undefined {\n if (transaction.type !== TransactionType.batch) {\n return transaction.type;\n }\n\n const nestedType = transaction.nestedTransactions?.find(\n (tx) => tx.type && enabledTypes.includes(tx.type),\n )?.type;\n\n return nestedType ?? transaction.type;\n}\n\n/**\n * Checks whether a transaction is a Money Account deposit.\n *\n * Handles both direct `moneyAccountDeposit` transactions and EIP-7702\n * batch transactions that contain a `moneyAccountDeposit` nested call.\n * Uses {@link resolveTransactionType} with `FIAT_ENABLED_TYPES` to\n * correctly skip non-deposit nested types (e.g. `tokenMethodApprove`).\n *\n * @param transaction - The transaction metadata to inspect.\n * @returns `true` if the transaction is a Money Account deposit.\n */\nexport function isMoneyAccountDepositTransaction(\n transaction: TransactionMeta,\n): boolean {\n return (\n resolveTransactionType(transaction, FIAT_ENABLED_TYPES) ===\n TransactionType.moneyAccountDeposit\n );\n}\n\n/**\n * Fetches the first matching Ramps quote for a fiat asset and payment method.\n *\n * @param options - Quote options.\n * @param options.adjustedAmount - Fiat amount sent to Ramps.\n * @param options.errorMessage - Error thrown when no matching quote is returned.\n * @param options.fiatAsset - Fiat asset to buy.\n * @param options.fiatPaymentMethod - Selected fiat payment method.\n * @param options.messenger - Controller messenger.\n * @param options.walletAddress - Wallet address that receives the on-ramped asset.\n * @returns The first matching Ramps quote.\n */\nexport async function getRampsQuote({\n adjustedAmount,\n errorMessage = 'No matching ramps quote found for selected provider',\n fiatAsset,\n fiatPaymentMethod,\n messenger,\n walletAddress,\n}: {\n adjustedAmount: number;\n errorMessage?: string;\n fiatAsset: TransactionPayFiatAsset;\n fiatPaymentMethod: string;\n messenger: TransactionPayControllerMessenger;\n walletAddress: string;\n}): Promise<RampsQuote> {\n const quotes = await messenger.call('RampsController:getQuotes', {\n amount: adjustedAmount,\n assetId: buildCaipAssetType(fiatAsset.chainId, fiatAsset.address),\n autoSelectProvider: true,\n fiat: DEFAULT_FIAT_CURRENCY,\n paymentMethods: [fiatPaymentMethod],\n restrictToKnownOrNativeProviders: true,\n walletAddress,\n });\n\n log('Fetched ramps quotes', {\n quotesCount: quotes.success?.length ?? 0,\n });\n\n const quote = quotes.success?.[0];\n\n if (!quote) {\n throw new Error(errorMessage);\n }\n\n return quote;\n}\n\n/**\n * Validates that a completed order's crypto asset matches the expected fiat asset.\n *\n * @param options - The validation options.\n * @param options.expectedAsset - The expected fiat asset derived from the transaction type.\n * @param options.orderCrypto - The crypto currency information from the completed order.\n * @param options.transactionId - Transaction ID for error reporting.\n */\nexport function validateOrderAsset({\n expectedAsset,\n orderCrypto,\n transactionId,\n}: {\n expectedAsset: TransactionPayFiatAsset;\n orderCrypto: RampsOrderCryptoCurrency | undefined;\n transactionId: string;\n}): void {\n const orderAssetId = orderCrypto?.assetId?.toLowerCase();\n const expectedAssetId = buildCaipAssetType(\n expectedAsset.chainId,\n expectedAsset.address,\n ).toLowerCase();\n const expectedChainId = expectedAssetId.split('/')[0];\n const orderChainId = orderCrypto?.chainId?.toLowerCase();\n\n if (orderAssetId && orderAssetId !== expectedAssetId) {\n throw new Error(\n `Order asset mismatch for transaction ${transactionId}: ` +\n `expected ${expectedAssetId}, got ${orderAssetId}`,\n );\n }\n\n if (orderChainId && orderChainId !== expectedChainId) {\n throw new Error(\n `Order chain mismatch for transaction ${transactionId}: ` +\n `expected ${expectedChainId}, got ${orderChainId}`,\n );\n }\n}\n\n/**\n * Result from {@link resolveSourceAmountRaw}.\n */\nexport type ResolvedSourceAmount = {\n /** Raw (atomic) source amount as a decimal string. */\n amountRaw: string;\n /**\n * Block number of the ramps settlement transaction as a 0x-prefixed hex\n * string. Populated when `order.txHash` is present and the on-chain receipt\n * was successfully fetched (ERC-20 only). Use this as the `fromBlock` for\n * CHOMP idempotency log queries — it reuses the receipt already fetched for\n * the amount and requires no additional network request.\n */\n fromBlock: Hex | undefined;\n};\n\n/**\n * Resolves the raw source amount for a completed fiat order.\n *\n * Attempts to read the actual transferred amount from the on-chain transaction\n * identified by `order.txHash`. If the on-chain read fails or returns\n * no amount, falls back to computing the amount from `order.cryptoAmount`.\n *\n * Also returns the receipt `blockNumber` from the ramps tx when available, so\n * callers can use it as a CHOMP idempotency baseline without any extra request.\n *\n * @param options - The resolution options.\n * @param options.messenger - Controller messenger for network access.\n * @param options.order - The completed on-ramp order.\n * @param options.fiatAsset - The fiat asset describing the expected token.\n * @param options.walletAddress - Recipient wallet address for on-chain lookup.\n * @returns The raw (atomic) source amount and optional receipt block number.\n */\nexport async function resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress,\n}: {\n messenger: TransactionPayControllerMessenger;\n order: RampsOrder;\n fiatAsset: TransactionPayFiatAsset;\n walletAddress: Hex;\n}): Promise<ResolvedSourceAmount> {\n if (order.txHash) {\n try {\n const { amountRaw: onChainAmount, blockNumber } =\n await getTransferredAmountFromTxHash({\n messenger,\n txHash: order.txHash,\n chainId: fiatAsset.chainId,\n tokenAddress: fiatAsset.address,\n walletAddress,\n });\n\n if (onChainAmount) {\n log('Resolved source amount from on-chain transaction', {\n txHash: order.txHash,\n onChainAmount,\n blockNumber,\n });\n return { amountRaw: onChainAmount, fromBlock: blockNumber };\n }\n } catch (error) {\n log(\n 'Failed to read on-chain amount, falling back to order.cryptoAmount',\n { txHash: order.txHash, error },\n );\n }\n }\n\n const tokenInfo = getTokenInfo(\n messenger,\n fiatAsset.address,\n fiatAsset.chainId,\n );\n\n if (!tokenInfo) {\n throw new Error(\n `Unable to resolve token info for fiat asset ${fiatAsset.address} on chain ${fiatAsset.chainId}`,\n );\n }\n\n const amountRaw = getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount: order.cryptoAmount,\n decimals: tokenInfo.decimals,\n });\n\n return { amountRaw, fromBlock: undefined };\n}\n\n/**\n * Converts the order's human-readable crypto amount to a raw token amount.\n *\n * @param options - The conversion options.\n * @param options.cryptoAmount - Human-readable crypto amount from the completed order.\n * @param options.decimals - Token decimals for the fiat asset.\n * @returns The raw token amount as a string.\n */\nexport function getRawSourceAmountFromOrderCryptoAmount({\n cryptoAmount,\n decimals,\n}: {\n cryptoAmount: RampsOrder['cryptoAmount'];\n decimals: number;\n}): string {\n const normalizedAmount = new BigNumber(String(cryptoAmount));\n\n if (!normalizedAmount.isFinite() || normalizedAmount.lte(0)) {\n throw new Error(\n `Invalid fiat order crypto amount: ${String(cryptoAmount)}`,\n );\n }\n\n const rawAmount = normalizedAmount\n .shiftedBy(decimals)\n .decimalPlaces(0, BigNumber.ROUND_DOWN)\n .toFixed(0);\n\n if (!new BigNumber(rawAmount).gt(0)) {\n throw new Error('Computed fiat order source amount is not positive');\n }\n\n return rawAmount;\n}\n\n/**\n * Validates that the relay exchange rate hasn't drifted significantly between\n * the original quoting phase and the post-settlement discovery quote.\n *\n * Compares the USD output/input ratio from both quotes. This normalises for\n * different source amounts (quoting phase uses a theoretical amount, discovery\n * uses the actual settled amount) so the comparison reflects genuine rate\n * movement rather than amount differences.\n *\n * @param options - The validation options.\n * @param options.originalQuote - Relay quote from the original quoting phase.\n * @param options.discoveryQuote - Relay quote from the post-settlement discovery.\n * @param options.maxRateDriftPercent - Maximum allowed rate drift percentage.\n * @param options.transactionId - Transaction ID for error reporting.\n */\nexport function validateRelayRateDrift({\n originalQuote,\n discoveryQuote,\n maxRateDriftPercent,\n transactionId,\n}: {\n originalQuote: RelayQuote;\n discoveryQuote: RelayQuote;\n maxRateDriftPercent: number;\n transactionId: string;\n}): void {\n const originalIn = new BigNumber(originalQuote.details.currencyIn.amountUsd);\n const originalOut = new BigNumber(\n originalQuote.details.currencyOut.amountUsd,\n );\n const discoveryIn = new BigNumber(\n discoveryQuote.details.currencyIn.amountUsd,\n );\n const discoveryOut = new BigNumber(\n discoveryQuote.details.currencyOut.amountUsd,\n );\n\n if (\n !originalIn.gt(0) ||\n !originalOut.gt(0) ||\n !discoveryIn.gt(0) ||\n !discoveryOut.gt(0)\n ) {\n return;\n }\n\n const originalRate = originalOut.dividedBy(originalIn);\n const discoveryRate = discoveryOut.dividedBy(discoveryIn);\n\n const driftPercent = originalRate\n .minus(discoveryRate)\n .dividedBy(originalRate)\n .multipliedBy(100);\n\n log('Relay rate drift check', {\n originalRate: originalRate.toFixed(6),\n discoveryRate: discoveryRate.toFixed(6),\n driftPercent: driftPercent.toFixed(2),\n maxRateDriftPercent,\n transactionId,\n });\n\n if (driftPercent.gt(maxRateDriftPercent)) {\n throw new Error(\n `Relay rate drift too high for transaction ` +\n `${driftPercent.toFixed(2)}% exceeds ${maxRateDriftPercent}% max`,\n );\n }\n}\n\n/**\n * Extracts the provider code from a ramps provider string.\n *\n * Accepts the canonical provider code (e.g. `transak-native`) and, for\n * backwards compatibility, the legacy path form (e.g. `/providers/transak-native`).\n *\n * @param provider - Canonical provider code, or legacy provider path.\n * @returns The provider code, or `null` if the format is invalid.\n */\nexport function extractProviderCode(\n provider: string | undefined,\n): string | null {\n if (!provider) {\n return null;\n }\n\n const parts = provider.split('/').filter(Boolean);\n\n if (parts[0] === 'providers') {\n return parts[1] ?? null;\n }\n\n return parts.length === 1 ? parts[0] : null;\n}\n\n/**\n * Provider codes that identify Transak's native (non-aggregator) integration.\n * Matches the codes emitted by `TransakService` for production and staging.\n */\nconst NATIVE_TRANSAK_PROVIDER_CODES = [\n 'transak-native',\n 'transak-native-staging',\n];\n\n/**\n * When the resolved ramps provider is Transak Native, fetches the native\n * Transak buy quote and returns its total fee so the estimate matches what\n * Transak Native actually charges.\n *\n * The native lookup (`/api/v2/lookup/quotes`) is an unauthenticated, API-key\n * only call, so it is safe to run at estimate time before the user signs in to\n * Transak. Returns `null` when the provider is not Transak Native, or when the\n * native lookup fails or returns an unusable fee, so the caller falls back to\n * the aggregator quote's fee.\n *\n * @param options - Native fee options.\n * @param options.adjustedAmount - Fiat amount (USD) sent to ramps.\n * @param options.fiatAsset - Fiat asset being bought.\n * @param options.fiatPaymentMethod - Selected fiat payment method.\n * @param options.fiatQuote - The resolved aggregator quote (used to detect native).\n * @param options.isFeeExcludedFromFiat - Whether Transak adds its fee on top of\n * the fiat amount (`true`) or carves it out of the amount (`false`). Must mirror\n * the eventual checkout mode so the estimate equals the charge.\n * @param options.messenger - Controller messenger.\n * @returns The native total fee as a BigNumber, or `null` to use the aggregator fee.\n */\nexport async function getNativeTransakRampsFee({\n adjustedAmount,\n fiatAsset,\n fiatPaymentMethod,\n fiatQuote,\n isFeeExcludedFromFiat,\n messenger,\n}: {\n adjustedAmount: number;\n fiatAsset: TransactionPayFiatAsset;\n fiatPaymentMethod: string;\n fiatQuote: RampsQuote;\n isFeeExcludedFromFiat: boolean;\n messenger: TransactionPayControllerMessenger;\n}): Promise<BigNumber | null> {\n const providerCode = extractProviderCode(fiatQuote.provider);\n\n if (!providerCode || !NATIVE_TRANSAK_PROVIDER_CODES.includes(providerCode)) {\n return null;\n }\n\n try {\n const assetId = buildCaipAssetType(fiatAsset.chainId, fiatAsset.address);\n const network = assetId.split('/')[0];\n\n const nativeQuote = await messenger.call(\n 'TransakService:getBuyQuote',\n DEFAULT_FIAT_CURRENCY,\n assetId,\n network,\n fiatPaymentMethod,\n String(adjustedAmount),\n isFeeExcludedFromFiat,\n );\n\n const fee = new BigNumber(nativeQuote.totalFee ?? NaN);\n\n if (!fee.isFinite() || fee.isLessThan(0)) {\n log(\n 'Native Transak quote returned an unusable fee; using aggregator fee',\n {\n totalFee: nativeQuote.totalFee,\n },\n );\n return null;\n }\n\n return fee;\n } catch (error) {\n log('Native Transak fee fetch failed; using aggregator fee', { error });\n return null;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"relay-quotes.d.ts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAGV,2BAA2B,EAG3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAkCxB,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,YAAY,CAAC;AAuBpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAkD5C"}
1
+ {"version":3,"file":"relay-quotes.d.ts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAGV,2BAA2B,EAG3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAkCxB,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,YAAY,CAAC;AAuBpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAkD5C"}
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable require-atomic-updates */
2
2
  import { Interface } from '@ethersproject/abi';
3
3
  import { toHex } from '@metamask/controller-utils';
4
- import { TransactionType } from '@metamask/transaction-controller';
4
+ import { hasTransactionType, TransactionType, } from '@metamask/transaction-controller';
5
5
  import { createModuleLogger } from '@metamask/utils';
6
6
  import { BigNumber } from 'bignumber.js';
7
7
  import { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM, CHAIN_ID_HYPERCORE, CHAIN_ID_POLYGON, HYPERCORE_USDC_ADDRESS, HYPERCORE_USDC_DECIMALS, NATIVE_TOKEN_ADDRESS, PERPS_DEPOSIT_TYPES, USDC_DECIMALS, PaymentOverride, } from '../../constants.js';
@@ -192,8 +192,10 @@ async function getSingleQuote(request, fullRequest) {
192
192
  }
193
193
  const hasTransactions = Boolean(body.txs?.length);
194
194
  const requiresExactOutput = hasTransactions ||
195
- transaction.type === TransactionType.perpsDepositAndOrder ||
196
- transaction.type === TransactionType.predictDepositAndOrder;
195
+ hasTransactionType(transaction, [
196
+ TransactionType.perpsDepositAndOrder,
197
+ TransactionType.predictDepositAndOrder,
198
+ ]);
197
199
  const finalBody = {
198
200
  ...body,
199
201
  amount: body.amount ??