@metamask-previews/transaction-pay-controller 27.0.0-preview-eb263b0ee → 27.0.0-preview-c61613ed2
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 +3 -2
- package/dist/strategy/fiat/fiat-direct-musd.cjs +5 -7
- package/dist/strategy/fiat/fiat-direct-musd.cjs.map +1 -1
- package/dist/strategy/fiat/fiat-direct-musd.d.cts.map +1 -1
- package/dist/strategy/fiat/fiat-direct-musd.d.mts.map +1 -1
- package/dist/strategy/fiat/fiat-direct-musd.mjs +6 -8
- package/dist/strategy/fiat/fiat-direct-musd.mjs.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.cjs +25 -4
- package/dist/strategy/fiat/fiat-quotes.cjs.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.d.cts.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.d.mts.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.mjs +26 -5
- package/dist/strategy/fiat/fiat-quotes.mjs.map +1 -1
- package/dist/strategy/fiat/utils.cjs +1 -75
- package/dist/strategy/fiat/utils.cjs.map +1 -1
- package/dist/strategy/fiat/utils.d.cts +0 -47
- package/dist/strategy/fiat/utils.d.cts.map +1 -1
- package/dist/strategy/fiat/utils.d.mts +0 -47
- package/dist/strategy/fiat/utils.d.mts.map +1 -1
- package/dist/strategy/fiat/utils.mjs +0 -71
- package/dist/strategy/fiat/utils.mjs.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -9,9 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Changed
|
|
11
11
|
|
|
12
|
-
- Use the ramps quote's `extraFee` as the MetaMask fee for fiat quotes instead of deriving it from a hardcoded percentage ([#9317](https://github.com/MetaMask/core/pull/9317))
|
|
13
|
-
- `fees.metaMask` now reflects the partner fee reported by the quote, including the zero-fee mUSD discount.
|
|
14
12
|
- Bump `@metamask/sentinel-api-service` from `^1.0.0` to `^1.0.1` ([#9972](https://github.com/MetaMask/core/pull/9972))
|
|
13
|
+
- Bump `@metamask/remote-feature-flag-controller` from `^6.0.0` to `^6.1.0` ([#9980](https://github.com/MetaMask/core/pull/9980))
|
|
14
|
+
- Bump `@metamask/ramps-controller` from `^20.0.0` to `^20.1.0` ([#10004](https://github.com/MetaMask/core/pull/10004))
|
|
15
|
+
- Bump `@metamask/ramps-controller` from `^20.1.0` to `^20.2.0` ([#10005](https://github.com/MetaMask/core/pull/10005))
|
|
15
16
|
|
|
16
17
|
## [27.0.0]
|
|
17
18
|
|
|
@@ -119,12 +119,7 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
|
|
|
119
119
|
cryptoAmount: fiatQuote.quote.amountOut,
|
|
120
120
|
decimals: tokenInfo.decimals,
|
|
121
121
|
});
|
|
122
|
-
const rampsProviderFee = (
|
|
123
|
-
// mUSD is not charged the partner fee on any payment method, but read it
|
|
124
|
-
// from the quote rather than assuming zero so the discount is driven by the
|
|
125
|
-
// ramps API. A non-zero value here means mUSD is being charged a partner
|
|
126
|
-
// fee upstream, which should surface rather than be hidden.
|
|
127
|
-
const metaMaskFee = (0, utils_js_1.getRampsMetaMaskFee)(fiatQuote).toString(10);
|
|
122
|
+
const rampsProviderFee = getRampsProviderFee(fiatQuote).toString(10);
|
|
128
123
|
const sourceAmountHuman = new bignumber_js_1.BigNumber(sourceAmountRaw)
|
|
129
124
|
.shiftedBy(-tokenInfo.decimals)
|
|
130
125
|
.toString(10);
|
|
@@ -132,7 +127,7 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
|
|
|
132
127
|
dust: { fiat: '0', usd: '0' },
|
|
133
128
|
estimatedDuration: 0,
|
|
134
129
|
fees: {
|
|
135
|
-
metaMask: { fiat:
|
|
130
|
+
metaMask: { fiat: '0', usd: '0' },
|
|
136
131
|
provider: { fiat: rampsProviderFee, usd: rampsProviderFee },
|
|
137
132
|
providerFiat: { fiat: rampsProviderFee, usd: rampsProviderFee },
|
|
138
133
|
sourceNetwork: {
|
|
@@ -167,4 +162,7 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
|
|
|
167
162
|
targetAmount: { fiat: amountFiat, usd: amountFiat },
|
|
168
163
|
};
|
|
169
164
|
}
|
|
165
|
+
function getRampsProviderFee(fiatQuote) {
|
|
166
|
+
return new bignumber_js_1.BigNumber(fiatQuote.quote.providerFee ?? 0).plus(fiatQuote.quote.networkFee ?? 0);
|
|
167
|
+
}
|
|
170
168
|
//# sourceMappingURL=fiat-direct-musd.cjs.map
|
|
@@ -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 getRampsMetaMaskFee,\n getRampsProviderFiatFee,\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 = getRampsProviderFiatFee(fiatQuote).toString(10);\n // mUSD is not charged the partner fee on any payment method, but read it\n // from the quote rather than assuming zero so the discount is driven by the\n // ramps API. A non-zero value here means mUSD is being charged a partner\n // fee upstream, which should surface rather than be hidden.\n const metaMaskFee = getRampsMetaMaskFee(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: metaMaskFee, usd: metaMaskFee },\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"]}
|
|
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 = 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 +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;
|
|
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 +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;
|
|
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"}
|
|
@@ -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 {
|
|
10
|
+
import { 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
|
/**
|
|
@@ -113,12 +113,7 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
|
|
|
113
113
|
cryptoAmount: fiatQuote.quote.amountOut,
|
|
114
114
|
decimals: tokenInfo.decimals,
|
|
115
115
|
});
|
|
116
|
-
const rampsProviderFee =
|
|
117
|
-
// mUSD is not charged the partner fee on any payment method, but read it
|
|
118
|
-
// from the quote rather than assuming zero so the discount is driven by the
|
|
119
|
-
// ramps API. A non-zero value here means mUSD is being charged a partner
|
|
120
|
-
// fee upstream, which should surface rather than be hidden.
|
|
121
|
-
const metaMaskFee = getRampsMetaMaskFee(fiatQuote).toString(10);
|
|
116
|
+
const rampsProviderFee = getRampsProviderFee(fiatQuote).toString(10);
|
|
122
117
|
const sourceAmountHuman = new BigNumber(sourceAmountRaw)
|
|
123
118
|
.shiftedBy(-tokenInfo.decimals)
|
|
124
119
|
.toString(10);
|
|
@@ -126,7 +121,7 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
|
|
|
126
121
|
dust: { fiat: '0', usd: '0' },
|
|
127
122
|
estimatedDuration: 0,
|
|
128
123
|
fees: {
|
|
129
|
-
metaMask: { fiat:
|
|
124
|
+
metaMask: { fiat: '0', usd: '0' },
|
|
130
125
|
provider: { fiat: rampsProviderFee, usd: rampsProviderFee },
|
|
131
126
|
providerFiat: { fiat: rampsProviderFee, usd: rampsProviderFee },
|
|
132
127
|
sourceNetwork: {
|
|
@@ -161,4 +156,7 @@ function combineDirectMusdFiatQuote({ amountFiat, fiatQuote, messenger, moneyAcc
|
|
|
161
156
|
targetAmount: { fiat: amountFiat, usd: amountFiat },
|
|
162
157
|
};
|
|
163
158
|
}
|
|
159
|
+
function getRampsProviderFee(fiatQuote) {
|
|
160
|
+
return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(fiatQuote.quote.networkFee ?? 0);
|
|
161
|
+
}
|
|
164
162
|
//# sourceMappingURL=fiat-direct-musd.mjs.map
|
|
@@ -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 getRampsMetaMaskFee,\n getRampsProviderFiatFee,\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 = getRampsProviderFiatFee(fiatQuote).toString(10);\n // mUSD is not charged the partner fee on any payment method, but read it\n // from the quote rather than assuming zero so the discount is driven by the\n // ramps API. A non-zero value here means mUSD is being charged a partner\n // fee upstream, which should surface rather than be hidden.\n const metaMaskFee = getRampsMetaMaskFee(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: metaMaskFee, usd: metaMaskFee },\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"]}
|
|
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 = 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"]}
|
|
@@ -122,6 +122,8 @@ async function executeFiatQuotePipeline(request, options) {
|
|
|
122
122
|
});
|
|
123
123
|
return [
|
|
124
124
|
combineQuotes({
|
|
125
|
+
adjustedAmountFiat: adjustedAmountFiat.toString(10),
|
|
126
|
+
amountFiat,
|
|
125
127
|
fiatQuote,
|
|
126
128
|
relayQuote,
|
|
127
129
|
}),
|
|
@@ -170,6 +172,8 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
|
|
|
170
172
|
* Combines fiat and relay legs into a single MM Pay fiat strategy quote.
|
|
171
173
|
*
|
|
172
174
|
* @param params - Combined quote inputs.
|
|
175
|
+
* @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.
|
|
176
|
+
* @param params.amountFiat - User-entered fiat amount.
|
|
173
177
|
* @param params.fiatQuote - Selected ramps quote.
|
|
174
178
|
* @param params.relayQuote - Estimated relay quote.
|
|
175
179
|
* @returns A single fiat strategy quote with split fee buckets.
|
|
@@ -181,17 +185,20 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
|
|
|
181
185
|
* Optional breakdown; client can derive relay portion via `provider - providerFiat`.
|
|
182
186
|
* - `fees.sourceNetwork` / `fees.targetNetwork`: Relay settlement network fees.
|
|
183
187
|
* Consumed by UI transaction fee row and tooltip network fee.
|
|
184
|
-
* - `fees.metaMask`:
|
|
188
|
+
* - `fees.metaMask`: MM Pay fee (currently 100 bps over `amountFiat + adjustedAmountFiat`).
|
|
185
189
|
* Consumed by UI transaction fee row and tooltip MetaMask fee.
|
|
186
190
|
* - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.
|
|
187
191
|
*/
|
|
188
|
-
function combineQuotes({ fiatQuote, relayQuote, }) {
|
|
189
|
-
const rampsProviderFee = (
|
|
192
|
+
function combineQuotes({ adjustedAmountFiat, amountFiat, fiatQuote, relayQuote, }) {
|
|
193
|
+
const rampsProviderFee = getRampsProviderFee(fiatQuote);
|
|
190
194
|
const totalProviderFee = new bignumber_js_1.BigNumber(relayQuote.fees.provider.usd)
|
|
191
195
|
.plus(rampsProviderFee)
|
|
192
196
|
.toString(10);
|
|
193
197
|
const rampsProviderFeeStr = rampsProviderFee.toString(10);
|
|
194
|
-
const metaMaskFee = (
|
|
198
|
+
const metaMaskFee = getMetaMaskFee({
|
|
199
|
+
adjustedAmountFiat,
|
|
200
|
+
amountFiat,
|
|
201
|
+
}).toString(10);
|
|
195
202
|
return {
|
|
196
203
|
...relayQuote,
|
|
197
204
|
fees: {
|
|
@@ -216,6 +223,17 @@ function combineQuotes({ fiatQuote, relayQuote, }) {
|
|
|
216
223
|
strategy: constants_js_1.TransactionPayStrategy.Fiat,
|
|
217
224
|
};
|
|
218
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Ramps providers handle network gas fees themselves but report them separately
|
|
228
|
+
* as `networkFee` alongside their `providerFee`. We combine both into a single
|
|
229
|
+
* ramps provider fee for the `providerFiat` breakdown.
|
|
230
|
+
*
|
|
231
|
+
* @param fiatQuote - The ramps quote containing provider and network fees.
|
|
232
|
+
* @returns Combined ramps provider fee as a BigNumber.
|
|
233
|
+
*/
|
|
234
|
+
function getRampsProviderFee(fiatQuote) {
|
|
235
|
+
return new bignumber_js_1.BigNumber(fiatQuote.quote.providerFee ?? 0).plus(fiatQuote.quote.networkFee ?? 0);
|
|
236
|
+
}
|
|
219
237
|
function getRelayTotalFeeUsd(relayQuote) {
|
|
220
238
|
return new bignumber_js_1.BigNumber(relayQuote.fees.provider.usd)
|
|
221
239
|
.plus(relayQuote.fees.sourceNetwork.estimate.usd)
|
|
@@ -227,4 +245,7 @@ function getNonGasRelayFeeUsd(relayQuote) {
|
|
|
227
245
|
.plus(relayQuote.fees.targetNetwork.usd)
|
|
228
246
|
.plus(relayQuote.fees.metaMask.usd);
|
|
229
247
|
}
|
|
248
|
+
function getMetaMaskFee({ adjustedAmountFiat, amountFiat, }) {
|
|
249
|
+
return new bignumber_js_1.BigNumber(amountFiat).plus(adjustedAmountFiat).dividedBy(100);
|
|
250
|
+
}
|
|
230
251
|
//# sourceMappingURL=fiat-quotes.cjs.map
|
|
@@ -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 getRampsMetaMaskFee,\n getRampsProviderFiatFee,\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 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.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`: MetaMask fee reported by the ramps quote as `extraFee`.\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 fiatQuote,\n relayQuote,\n}: {\n fiatQuote: RampsQuote;\n relayQuote: TransactionPayQuote<RelayQuote>;\n}): TransactionPayQuote<FiatQuote> {\n const rampsProviderFee = getRampsProviderFiatFee(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 = getRampsMetaMaskFee(fiatQuote).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\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"]}
|
|
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 +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;
|
|
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 +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;
|
|
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"}
|
|
@@ -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,
|
|
9
|
+
import { deriveFiatAssetForFiatPayment, 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.
|
|
@@ -118,6 +118,8 @@ async function executeFiatQuotePipeline(request, options) {
|
|
|
118
118
|
});
|
|
119
119
|
return [
|
|
120
120
|
combineQuotes({
|
|
121
|
+
adjustedAmountFiat: adjustedAmountFiat.toString(10),
|
|
122
|
+
amountFiat,
|
|
121
123
|
fiatQuote,
|
|
122
124
|
relayQuote,
|
|
123
125
|
}),
|
|
@@ -166,6 +168,8 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
|
|
|
166
168
|
* Combines fiat and relay legs into a single MM Pay fiat strategy quote.
|
|
167
169
|
*
|
|
168
170
|
* @param params - Combined quote inputs.
|
|
171
|
+
* @param params.adjustedAmountFiat - Fiat amount sent to ramps after adding relay fee estimate.
|
|
172
|
+
* @param params.amountFiat - User-entered fiat amount.
|
|
169
173
|
* @param params.fiatQuote - Selected ramps quote.
|
|
170
174
|
* @param params.relayQuote - Estimated relay quote.
|
|
171
175
|
* @returns A single fiat strategy quote with split fee buckets.
|
|
@@ -177,17 +181,20 @@ function buildRelayRequestFromAmountFiat({ amountFiat, fiatAsset, messenger, req
|
|
|
177
181
|
* Optional breakdown; client can derive relay portion via `provider - providerFiat`.
|
|
178
182
|
* - `fees.sourceNetwork` / `fees.targetNetwork`: Relay settlement network fees.
|
|
179
183
|
* Consumed by UI transaction fee row and tooltip network fee.
|
|
180
|
-
* - `fees.metaMask`:
|
|
184
|
+
* - `fees.metaMask`: MM Pay fee (currently 100 bps over `amountFiat + adjustedAmountFiat`).
|
|
181
185
|
* Consumed by UI transaction fee row and tooltip MetaMask fee.
|
|
182
186
|
* - `totals.total` should represent Amount + Transaction Fee using the totals pipeline.
|
|
183
187
|
*/
|
|
184
|
-
function combineQuotes({ fiatQuote, relayQuote, }) {
|
|
185
|
-
const rampsProviderFee =
|
|
188
|
+
function combineQuotes({ adjustedAmountFiat, amountFiat, fiatQuote, relayQuote, }) {
|
|
189
|
+
const rampsProviderFee = getRampsProviderFee(fiatQuote);
|
|
186
190
|
const totalProviderFee = new BigNumber(relayQuote.fees.provider.usd)
|
|
187
191
|
.plus(rampsProviderFee)
|
|
188
192
|
.toString(10);
|
|
189
193
|
const rampsProviderFeeStr = rampsProviderFee.toString(10);
|
|
190
|
-
const metaMaskFee =
|
|
194
|
+
const metaMaskFee = getMetaMaskFee({
|
|
195
|
+
adjustedAmountFiat,
|
|
196
|
+
amountFiat,
|
|
197
|
+
}).toString(10);
|
|
191
198
|
return {
|
|
192
199
|
...relayQuote,
|
|
193
200
|
fees: {
|
|
@@ -212,6 +219,17 @@ function combineQuotes({ fiatQuote, relayQuote, }) {
|
|
|
212
219
|
strategy: TransactionPayStrategy.Fiat,
|
|
213
220
|
};
|
|
214
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Ramps providers handle network gas fees themselves but report them separately
|
|
224
|
+
* as `networkFee` alongside their `providerFee`. We combine both into a single
|
|
225
|
+
* ramps provider fee for the `providerFiat` breakdown.
|
|
226
|
+
*
|
|
227
|
+
* @param fiatQuote - The ramps quote containing provider and network fees.
|
|
228
|
+
* @returns Combined ramps provider fee as a BigNumber.
|
|
229
|
+
*/
|
|
230
|
+
function getRampsProviderFee(fiatQuote) {
|
|
231
|
+
return new BigNumber(fiatQuote.quote.providerFee ?? 0).plus(fiatQuote.quote.networkFee ?? 0);
|
|
232
|
+
}
|
|
215
233
|
function getRelayTotalFeeUsd(relayQuote) {
|
|
216
234
|
return new BigNumber(relayQuote.fees.provider.usd)
|
|
217
235
|
.plus(relayQuote.fees.sourceNetwork.estimate.usd)
|
|
@@ -223,4 +241,7 @@ function getNonGasRelayFeeUsd(relayQuote) {
|
|
|
223
241
|
.plus(relayQuote.fees.targetNetwork.usd)
|
|
224
242
|
.plus(relayQuote.fees.metaMask.usd);
|
|
225
243
|
}
|
|
244
|
+
function getMetaMaskFee({ adjustedAmountFiat, amountFiat, }) {
|
|
245
|
+
return new BigNumber(amountFiat).plus(adjustedAmountFiat).dividedBy(100);
|
|
246
|
+
}
|
|
226
247
|
//# sourceMappingURL=fiat-quotes.mjs.map
|
|
@@ -1 +1 @@
|
|
|
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 getRampsMetaMaskFee,\n getRampsProviderFiatFee,\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 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.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`: MetaMask fee reported by the ramps quote as `extraFee`.\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 fiatQuote,\n relayQuote,\n}: {\n fiatQuote: RampsQuote;\n relayQuote: TransactionPayQuote<RelayQuote>;\n}): TransactionPayQuote<FiatQuote> {\n const rampsProviderFee = getRampsProviderFiatFee(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 = getRampsMetaMaskFee(fiatQuote).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\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"]}
|
|
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 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,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.extractProviderCode = exports.validateRelayRateDrift = exports.getRawSourceAmountFromOrderCryptoAmount = exports.resolveSourceAmountRaw = exports.validateOrderAsset = exports.getRampsQuote = exports.isMoneyAccountDepositTransaction = exports.resolveTransactionType = exports.deriveFiatAssetForFiatPayment = void 0;
|
|
4
4
|
const transaction_controller_1 = require("@metamask/transaction-controller");
|
|
5
5
|
const utils_1 = require("@metamask/utils");
|
|
6
6
|
const bignumber_js_1 = require("bignumber.js");
|
|
@@ -246,78 +246,4 @@ function extractProviderCode(provider) {
|
|
|
246
246
|
return parts.length === 1 ? parts[0] : null;
|
|
247
247
|
}
|
|
248
248
|
exports.extractProviderCode = extractProviderCode;
|
|
249
|
-
/**
|
|
250
|
-
* Coerces a quote fee field into a usable non-negative amount.
|
|
251
|
-
*
|
|
252
|
-
* Ramps quotes type their fee fields as `number | string | undefined`, and a
|
|
253
|
-
* provider can report a value we cannot use (missing, `NaN`, or negative).
|
|
254
|
-
* Treating those as zero matches how the rest of the ramps surface reads fee
|
|
255
|
-
* fields (`partnerFees ?? 0` in the client analytics payloads, `extraFee ?? 0`
|
|
256
|
-
* in the aggregator quote list), so quotes stay usable instead of being
|
|
257
|
-
* discarded over a single bad field.
|
|
258
|
-
*
|
|
259
|
-
* @param value - Raw fee value from a ramps quote.
|
|
260
|
-
* @returns The fee as a non-negative finite BigNumber, or zero.
|
|
261
|
-
*/
|
|
262
|
-
function getSafeFee(value) {
|
|
263
|
-
const fee = new bignumber_js_1.BigNumber(value ?? 0);
|
|
264
|
-
return fee.isFinite() && fee.isGreaterThanOrEqualTo(0)
|
|
265
|
-
? fee
|
|
266
|
-
: new bignumber_js_1.BigNumber(0);
|
|
267
|
-
}
|
|
268
|
-
exports.getSafeFee = getSafeFee;
|
|
269
|
-
/**
|
|
270
|
-
* Combined on-ramp provider fee for the `providerFiat` breakdown.
|
|
271
|
-
*
|
|
272
|
-
* Ramps providers handle network gas fees themselves but report them
|
|
273
|
-
* separately as `networkFee` alongside their own `providerFee`. Both are the
|
|
274
|
-
* on-ramp's cost, so they combine into a single bucket. The partner
|
|
275
|
-
* (MetaMask) fee is deliberately excluded; it is reported separately by
|
|
276
|
-
* {@link getRampsMetaMaskFee} and would otherwise be counted twice.
|
|
277
|
-
*
|
|
278
|
-
* @param fiatQuote - The ramps quote containing provider and network fees.
|
|
279
|
-
* @returns Combined on-ramp provider fee.
|
|
280
|
-
*/
|
|
281
|
-
function getRampsProviderFiatFee(fiatQuote) {
|
|
282
|
-
return getSafeFee(fiatQuote.quote.providerFee).plus(getSafeFee(fiatQuote.quote.networkFee));
|
|
283
|
-
}
|
|
284
|
-
exports.getRampsProviderFiatFee = getRampsProviderFiatFee;
|
|
285
|
-
/**
|
|
286
|
-
* MetaMask's partner fee for a ramps quote.
|
|
287
|
-
*
|
|
288
|
-
* The ramps API reports it as `extraFee`, disjoint from `providerFee` and
|
|
289
|
-
* `networkFee` (the three sum to `totalFees`). Reading it from the quote is
|
|
290
|
-
* what lets the fee vary per quote, including the zero partner fee charged on
|
|
291
|
-
* mUSD.
|
|
292
|
-
*
|
|
293
|
-
* `extraFee` needs a fallback because the ramps backend coerces a missing
|
|
294
|
-
* partner fee to `0`, making an absent field indistinguishable from a genuine
|
|
295
|
-
* zero. That matters more than a display glitch: `fees.metaMask` is an addend
|
|
296
|
-
* of `totals.total`, and the client submits `total - providerFiat` as the
|
|
297
|
-
* amount to buy, so silently reading `0` would undercharge. When the quote
|
|
298
|
-
* also reports `totalFees`, recover the partner fee as the remainder instead.
|
|
299
|
-
*
|
|
300
|
-
* @param fiatQuote - The ramps quote to read fees from.
|
|
301
|
-
* @returns MetaMask's partner fee, or zero when the quote reports none.
|
|
302
|
-
*/
|
|
303
|
-
function getRampsMetaMaskFee(fiatQuote) {
|
|
304
|
-
const extraFee = getSafeFee(fiatQuote.quote.extraFee);
|
|
305
|
-
if (extraFee.isGreaterThan(0)) {
|
|
306
|
-
return extraFee;
|
|
307
|
-
}
|
|
308
|
-
const { totalFees } = fiatQuote.quote;
|
|
309
|
-
if (totalFees === undefined) {
|
|
310
|
-
return extraFee;
|
|
311
|
-
}
|
|
312
|
-
const remainder = getSafeFee(totalFees).minus(getRampsProviderFiatFee(fiatQuote));
|
|
313
|
-
if (remainder.isGreaterThan(0)) {
|
|
314
|
-
log('Recovered MetaMask fee from quote total fees', {
|
|
315
|
-
extraFee: extraFee.toString(10),
|
|
316
|
-
recovered: remainder.toString(10),
|
|
317
|
-
});
|
|
318
|
-
return remainder;
|
|
319
|
-
}
|
|
320
|
-
return extraFee;
|
|
321
|
-
}
|
|
322
|
-
exports.getRampsMetaMaskFee = getRampsMetaMaskFee;
|
|
323
249
|
//# sourceMappingURL=utils.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","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 * Coerces a quote fee field into a usable non-negative amount.\n *\n * Ramps quotes type their fee fields as `number | string | undefined`, and a\n * provider can report a value we cannot use (missing, `NaN`, or negative).\n * Treating those as zero matches how the rest of the ramps surface reads fee\n * fields (`partnerFees ?? 0` in the client analytics payloads, `extraFee ?? 0`\n * in the aggregator quote list), so quotes stay usable instead of being\n * discarded over a single bad field.\n *\n * @param value - Raw fee value from a ramps quote.\n * @returns The fee as a non-negative finite BigNumber, or zero.\n */\nexport function 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\n/**\n * Combined on-ramp provider fee for the `providerFiat` breakdown.\n *\n * Ramps providers handle network gas fees themselves but report them\n * separately as `networkFee` alongside their own `providerFee`. Both are the\n * on-ramp's cost, so they combine into a single bucket. The partner\n * (MetaMask) fee is deliberately excluded; it is reported separately by\n * {@link getRampsMetaMaskFee} and would otherwise be counted twice.\n *\n * @param fiatQuote - The ramps quote containing provider and network fees.\n * @returns Combined on-ramp provider fee.\n */\nexport function getRampsProviderFiatFee(fiatQuote: RampsQuote): BigNumber {\n return getSafeFee(fiatQuote.quote.providerFee).plus(\n getSafeFee(fiatQuote.quote.networkFee),\n );\n}\n\n/**\n * MetaMask's partner fee for a ramps quote.\n *\n * The ramps API reports it as `extraFee`, disjoint from `providerFee` and\n * `networkFee` (the three sum to `totalFees`). Reading it from the quote is\n * what lets the fee vary per quote, including the zero partner fee charged on\n * mUSD.\n *\n * `extraFee` needs a fallback because the ramps backend coerces a missing\n * partner fee to `0`, making an absent field indistinguishable from a genuine\n * zero. That matters more than a display glitch: `fees.metaMask` is an addend\n * of `totals.total`, and the client submits `total - providerFiat` as the\n * amount to buy, so silently reading `0` would undercharge. When the quote\n * also reports `totalFees`, recover the partner fee as the remainder instead.\n *\n * @param fiatQuote - The ramps quote to read fees from.\n * @returns MetaMask's partner fee, or zero when the quote reports none.\n */\nexport function getRampsMetaMaskFee(fiatQuote: RampsQuote): BigNumber {\n const extraFee = getSafeFee(fiatQuote.quote.extraFee);\n\n if (extraFee.isGreaterThan(0)) {\n return extraFee;\n }\n\n const { totalFees } = fiatQuote.quote;\n\n if (totalFees === undefined) {\n return extraFee;\n }\n\n const remainder = getSafeFee(totalFees).minus(\n getRampsProviderFiatFee(fiatQuote),\n );\n\n if (remainder.isGreaterThan(0)) {\n log('Recovered MetaMask fee from quote total fees', {\n extraFee: extraFee.toString(10),\n recovered: remainder.toString(10),\n });\n return remainder;\n }\n\n return extraFee;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"utils.cjs","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"]}
|
|
@@ -2,7 +2,6 @@ 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";
|
|
6
5
|
import type { TransactionPayControllerMessenger } from "../../types.cjs";
|
|
7
6
|
import type { RelayQuote } from "../relay/types.cjs";
|
|
8
7
|
import type { TransactionPayFiatAsset } from "./constants.cjs";
|
|
@@ -146,50 +145,4 @@ export declare function validateRelayRateDrift({ originalQuote, discoveryQuote,
|
|
|
146
145
|
* @returns The provider code, or `null` if the format is invalid.
|
|
147
146
|
*/
|
|
148
147
|
export declare function extractProviderCode(provider: string | undefined): string | null;
|
|
149
|
-
/**
|
|
150
|
-
* Coerces a quote fee field into a usable non-negative amount.
|
|
151
|
-
*
|
|
152
|
-
* Ramps quotes type their fee fields as `number | string | undefined`, and a
|
|
153
|
-
* provider can report a value we cannot use (missing, `NaN`, or negative).
|
|
154
|
-
* Treating those as zero matches how the rest of the ramps surface reads fee
|
|
155
|
-
* fields (`partnerFees ?? 0` in the client analytics payloads, `extraFee ?? 0`
|
|
156
|
-
* in the aggregator quote list), so quotes stay usable instead of being
|
|
157
|
-
* discarded over a single bad field.
|
|
158
|
-
*
|
|
159
|
-
* @param value - Raw fee value from a ramps quote.
|
|
160
|
-
* @returns The fee as a non-negative finite BigNumber, or zero.
|
|
161
|
-
*/
|
|
162
|
-
export declare function getSafeFee(value: BigNumber.Value | undefined): BigNumber;
|
|
163
|
-
/**
|
|
164
|
-
* Combined on-ramp provider fee for the `providerFiat` breakdown.
|
|
165
|
-
*
|
|
166
|
-
* Ramps providers handle network gas fees themselves but report them
|
|
167
|
-
* separately as `networkFee` alongside their own `providerFee`. Both are the
|
|
168
|
-
* on-ramp's cost, so they combine into a single bucket. The partner
|
|
169
|
-
* (MetaMask) fee is deliberately excluded; it is reported separately by
|
|
170
|
-
* {@link getRampsMetaMaskFee} and would otherwise be counted twice.
|
|
171
|
-
*
|
|
172
|
-
* @param fiatQuote - The ramps quote containing provider and network fees.
|
|
173
|
-
* @returns Combined on-ramp provider fee.
|
|
174
|
-
*/
|
|
175
|
-
export declare function getRampsProviderFiatFee(fiatQuote: RampsQuote): BigNumber;
|
|
176
|
-
/**
|
|
177
|
-
* MetaMask's partner fee for a ramps quote.
|
|
178
|
-
*
|
|
179
|
-
* The ramps API reports it as `extraFee`, disjoint from `providerFee` and
|
|
180
|
-
* `networkFee` (the three sum to `totalFees`). Reading it from the quote is
|
|
181
|
-
* what lets the fee vary per quote, including the zero partner fee charged on
|
|
182
|
-
* mUSD.
|
|
183
|
-
*
|
|
184
|
-
* `extraFee` needs a fallback because the ramps backend coerces a missing
|
|
185
|
-
* partner fee to `0`, making an absent field indistinguishable from a genuine
|
|
186
|
-
* zero. That matters more than a display glitch: `fees.metaMask` is an addend
|
|
187
|
-
* of `totals.total`, and the client submits `total - providerFiat` as the
|
|
188
|
-
* amount to buy, so silently reading `0` would undercharge. When the quote
|
|
189
|
-
* also reports `totalFees`, recover the partner fee as the remainder instead.
|
|
190
|
-
*
|
|
191
|
-
* @param fiatQuote - The ramps quote to read fees from.
|
|
192
|
-
* @returns MetaMask's partner fee, or zero when the quote reports none.
|
|
193
|
-
*/
|
|
194
|
-
export declare function getRampsMetaMaskFee(fiatQuote: RampsQuote): BigNumber;
|
|
195
148
|
//# sourceMappingURL=utils.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,IAAI,UAAU,EACnB,UAAU,EACV,wBAAwB,EACzB,mCAAmC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AACxE,OAAO,EAAE,eAAe,EAAE,yCAAyC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;
|
|
1
|
+
{"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,IAAI,UAAU,EACnB,UAAU,EACV,wBAAwB,EACzB,mCAAmC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AACxE,OAAO,EAAE,eAAe,EAAE,yCAAyC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EAAE,iCAAiC,EAAE,wBAAuB;AAOxE,OAAO,KAAK,EAAE,UAAU,EAAE,2BAA0B;AACpD,OAAO,KAAK,EAAE,uBAAuB,EAAE,wBAAuB;AAK9D,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,iCAAiC,GAC3C,uBAAuB,CAKzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,eAAe,EAC5B,YAAY,EAAE,eAAe,EAAE,GAC9B,eAAe,GAAG,SAAS,CAU7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,eAAe,GAC3B,OAAO,CAKT;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,EAClC,cAAc,EACd,YAAoE,EACpE,SAAS,EACT,iBAAiB,EACjB,SAAS,EACT,aAAa,GACd,EAAE;IACD,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,uBAAuB,CAAC;IACnC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,iCAAiC,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,UAAU,CAAC,CAsBtB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,aAAa,EACb,WAAW,EACX,aAAa,GACd,EAAE;IACD,aAAa,EAAE,uBAAuB,CAAC;IACvC,WAAW,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAClD,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CAsBP;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,SAAS,EAAE,GAAG,GAAG,SAAS,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,SAAS,EACT,KAAK,EACL,SAAS,EACT,aAAa,GACd,EAAE;IACD,SAAS,EAAE,iCAAiC,CAAC;IAC7C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,uBAAuB,CAAC;IACnC,aAAa,EAAE,GAAG,CAAC;CACpB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA8ChC;AAED;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,CAAC,EACtD,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAmBT;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,aAAa,GACd,EAAE;IACD,aAAa,EAAE,UAAU,CAAC;IAC1B,cAAc,EAAE,UAAU,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CA2CP;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,IAAI,CAYf"}
|
|
@@ -2,7 +2,6 @@ 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";
|
|
6
5
|
import type { TransactionPayControllerMessenger } from "../../types.mjs";
|
|
7
6
|
import type { RelayQuote } from "../relay/types.mjs";
|
|
8
7
|
import type { TransactionPayFiatAsset } from "./constants.mjs";
|
|
@@ -146,50 +145,4 @@ export declare function validateRelayRateDrift({ originalQuote, discoveryQuote,
|
|
|
146
145
|
* @returns The provider code, or `null` if the format is invalid.
|
|
147
146
|
*/
|
|
148
147
|
export declare function extractProviderCode(provider: string | undefined): string | null;
|
|
149
|
-
/**
|
|
150
|
-
* Coerces a quote fee field into a usable non-negative amount.
|
|
151
|
-
*
|
|
152
|
-
* Ramps quotes type their fee fields as `number | string | undefined`, and a
|
|
153
|
-
* provider can report a value we cannot use (missing, `NaN`, or negative).
|
|
154
|
-
* Treating those as zero matches how the rest of the ramps surface reads fee
|
|
155
|
-
* fields (`partnerFees ?? 0` in the client analytics payloads, `extraFee ?? 0`
|
|
156
|
-
* in the aggregator quote list), so quotes stay usable instead of being
|
|
157
|
-
* discarded over a single bad field.
|
|
158
|
-
*
|
|
159
|
-
* @param value - Raw fee value from a ramps quote.
|
|
160
|
-
* @returns The fee as a non-negative finite BigNumber, or zero.
|
|
161
|
-
*/
|
|
162
|
-
export declare function getSafeFee(value: BigNumber.Value | undefined): BigNumber;
|
|
163
|
-
/**
|
|
164
|
-
* Combined on-ramp provider fee for the `providerFiat` breakdown.
|
|
165
|
-
*
|
|
166
|
-
* Ramps providers handle network gas fees themselves but report them
|
|
167
|
-
* separately as `networkFee` alongside their own `providerFee`. Both are the
|
|
168
|
-
* on-ramp's cost, so they combine into a single bucket. The partner
|
|
169
|
-
* (MetaMask) fee is deliberately excluded; it is reported separately by
|
|
170
|
-
* {@link getRampsMetaMaskFee} and would otherwise be counted twice.
|
|
171
|
-
*
|
|
172
|
-
* @param fiatQuote - The ramps quote containing provider and network fees.
|
|
173
|
-
* @returns Combined on-ramp provider fee.
|
|
174
|
-
*/
|
|
175
|
-
export declare function getRampsProviderFiatFee(fiatQuote: RampsQuote): BigNumber;
|
|
176
|
-
/**
|
|
177
|
-
* MetaMask's partner fee for a ramps quote.
|
|
178
|
-
*
|
|
179
|
-
* The ramps API reports it as `extraFee`, disjoint from `providerFee` and
|
|
180
|
-
* `networkFee` (the three sum to `totalFees`). Reading it from the quote is
|
|
181
|
-
* what lets the fee vary per quote, including the zero partner fee charged on
|
|
182
|
-
* mUSD.
|
|
183
|
-
*
|
|
184
|
-
* `extraFee` needs a fallback because the ramps backend coerces a missing
|
|
185
|
-
* partner fee to `0`, making an absent field indistinguishable from a genuine
|
|
186
|
-
* zero. That matters more than a display glitch: `fees.metaMask` is an addend
|
|
187
|
-
* of `totals.total`, and the client submits `total - providerFiat` as the
|
|
188
|
-
* amount to buy, so silently reading `0` would undercharge. When the quote
|
|
189
|
-
* also reports `totalFees`, recover the partner fee as the remainder instead.
|
|
190
|
-
*
|
|
191
|
-
* @param fiatQuote - The ramps quote to read fees from.
|
|
192
|
-
* @returns MetaMask's partner fee, or zero when the quote reports none.
|
|
193
|
-
*/
|
|
194
|
-
export declare function getRampsMetaMaskFee(fiatQuote: RampsQuote): BigNumber;
|
|
195
148
|
//# sourceMappingURL=utils.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,IAAI,UAAU,EACnB,UAAU,EACV,wBAAwB,EACzB,mCAAmC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AACxE,OAAO,EAAE,eAAe,EAAE,yCAAyC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;
|
|
1
|
+
{"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,IAAI,UAAU,EACnB,UAAU,EACV,wBAAwB,EACzB,mCAAmC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AACxE,OAAO,EAAE,eAAe,EAAE,yCAAyC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EAAE,iCAAiC,EAAE,wBAAuB;AAOxE,OAAO,KAAK,EAAE,UAAU,EAAE,2BAA0B;AACpD,OAAO,KAAK,EAAE,uBAAuB,EAAE,wBAAuB;AAK9D,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,iCAAiC,GAC3C,uBAAuB,CAKzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,eAAe,EAC5B,YAAY,EAAE,eAAe,EAAE,GAC9B,eAAe,GAAG,SAAS,CAU7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,eAAe,GAC3B,OAAO,CAKT;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,EAClC,cAAc,EACd,YAAoE,EACpE,SAAS,EACT,iBAAiB,EACjB,SAAS,EACT,aAAa,GACd,EAAE;IACD,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,uBAAuB,CAAC;IACnC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,iCAAiC,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,UAAU,CAAC,CAsBtB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,aAAa,EACb,WAAW,EACX,aAAa,GACd,EAAE;IACD,aAAa,EAAE,uBAAuB,CAAC;IACvC,WAAW,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAClD,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CAsBP;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,SAAS,EAAE,GAAG,GAAG,SAAS,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,SAAS,EACT,KAAK,EACL,SAAS,EACT,aAAa,GACd,EAAE;IACD,SAAS,EAAE,iCAAiC,CAAC;IAC7C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,uBAAuB,CAAC;IACnC,aAAa,EAAE,GAAG,CAAC;CACpB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA8ChC;AAED;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,CAAC,EACtD,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAmBT;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,aAAa,GACd,EAAE;IACD,aAAa,EAAE,UAAU,CAAC;IAC1B,cAAc,EAAE,UAAU,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CA2CP;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,IAAI,CAYf"}
|
|
@@ -234,75 +234,4 @@ export function extractProviderCode(provider) {
|
|
|
234
234
|
}
|
|
235
235
|
return parts.length === 1 ? parts[0] : null;
|
|
236
236
|
}
|
|
237
|
-
/**
|
|
238
|
-
* Coerces a quote fee field into a usable non-negative amount.
|
|
239
|
-
*
|
|
240
|
-
* Ramps quotes type their fee fields as `number | string | undefined`, and a
|
|
241
|
-
* provider can report a value we cannot use (missing, `NaN`, or negative).
|
|
242
|
-
* Treating those as zero matches how the rest of the ramps surface reads fee
|
|
243
|
-
* fields (`partnerFees ?? 0` in the client analytics payloads, `extraFee ?? 0`
|
|
244
|
-
* in the aggregator quote list), so quotes stay usable instead of being
|
|
245
|
-
* discarded over a single bad field.
|
|
246
|
-
*
|
|
247
|
-
* @param value - Raw fee value from a ramps quote.
|
|
248
|
-
* @returns The fee as a non-negative finite BigNumber, or zero.
|
|
249
|
-
*/
|
|
250
|
-
export function getSafeFee(value) {
|
|
251
|
-
const fee = new BigNumber(value ?? 0);
|
|
252
|
-
return fee.isFinite() && fee.isGreaterThanOrEqualTo(0)
|
|
253
|
-
? fee
|
|
254
|
-
: new BigNumber(0);
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Combined on-ramp provider fee for the `providerFiat` breakdown.
|
|
258
|
-
*
|
|
259
|
-
* Ramps providers handle network gas fees themselves but report them
|
|
260
|
-
* separately as `networkFee` alongside their own `providerFee`. Both are the
|
|
261
|
-
* on-ramp's cost, so they combine into a single bucket. The partner
|
|
262
|
-
* (MetaMask) fee is deliberately excluded; it is reported separately by
|
|
263
|
-
* {@link getRampsMetaMaskFee} and would otherwise be counted twice.
|
|
264
|
-
*
|
|
265
|
-
* @param fiatQuote - The ramps quote containing provider and network fees.
|
|
266
|
-
* @returns Combined on-ramp provider fee.
|
|
267
|
-
*/
|
|
268
|
-
export function getRampsProviderFiatFee(fiatQuote) {
|
|
269
|
-
return getSafeFee(fiatQuote.quote.providerFee).plus(getSafeFee(fiatQuote.quote.networkFee));
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* MetaMask's partner fee for a ramps quote.
|
|
273
|
-
*
|
|
274
|
-
* The ramps API reports it as `extraFee`, disjoint from `providerFee` and
|
|
275
|
-
* `networkFee` (the three sum to `totalFees`). Reading it from the quote is
|
|
276
|
-
* what lets the fee vary per quote, including the zero partner fee charged on
|
|
277
|
-
* mUSD.
|
|
278
|
-
*
|
|
279
|
-
* `extraFee` needs a fallback because the ramps backend coerces a missing
|
|
280
|
-
* partner fee to `0`, making an absent field indistinguishable from a genuine
|
|
281
|
-
* zero. That matters more than a display glitch: `fees.metaMask` is an addend
|
|
282
|
-
* of `totals.total`, and the client submits `total - providerFiat` as the
|
|
283
|
-
* amount to buy, so silently reading `0` would undercharge. When the quote
|
|
284
|
-
* also reports `totalFees`, recover the partner fee as the remainder instead.
|
|
285
|
-
*
|
|
286
|
-
* @param fiatQuote - The ramps quote to read fees from.
|
|
287
|
-
* @returns MetaMask's partner fee, or zero when the quote reports none.
|
|
288
|
-
*/
|
|
289
|
-
export function getRampsMetaMaskFee(fiatQuote) {
|
|
290
|
-
const extraFee = getSafeFee(fiatQuote.quote.extraFee);
|
|
291
|
-
if (extraFee.isGreaterThan(0)) {
|
|
292
|
-
return extraFee;
|
|
293
|
-
}
|
|
294
|
-
const { totalFees } = fiatQuote.quote;
|
|
295
|
-
if (totalFees === undefined) {
|
|
296
|
-
return extraFee;
|
|
297
|
-
}
|
|
298
|
-
const remainder = getSafeFee(totalFees).minus(getRampsProviderFiatFee(fiatQuote));
|
|
299
|
-
if (remainder.isGreaterThan(0)) {
|
|
300
|
-
log('Recovered MetaMask fee from quote total fees', {
|
|
301
|
-
extraFee: extraFee.toString(10),
|
|
302
|
-
recovered: remainder.toString(10),
|
|
303
|
-
});
|
|
304
|
-
return remainder;
|
|
305
|
-
}
|
|
306
|
-
return extraFee;
|
|
307
|
-
}
|
|
308
237
|
//# sourceMappingURL=utils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","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 * Coerces a quote fee field into a usable non-negative amount.\n *\n * Ramps quotes type their fee fields as `number | string | undefined`, and a\n * provider can report a value we cannot use (missing, `NaN`, or negative).\n * Treating those as zero matches how the rest of the ramps surface reads fee\n * fields (`partnerFees ?? 0` in the client analytics payloads, `extraFee ?? 0`\n * in the aggregator quote list), so quotes stay usable instead of being\n * discarded over a single bad field.\n *\n * @param value - Raw fee value from a ramps quote.\n * @returns The fee as a non-negative finite BigNumber, or zero.\n */\nexport function 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\n/**\n * Combined on-ramp provider fee for the `providerFiat` breakdown.\n *\n * Ramps providers handle network gas fees themselves but report them\n * separately as `networkFee` alongside their own `providerFee`. Both are the\n * on-ramp's cost, so they combine into a single bucket. The partner\n * (MetaMask) fee is deliberately excluded; it is reported separately by\n * {@link getRampsMetaMaskFee} and would otherwise be counted twice.\n *\n * @param fiatQuote - The ramps quote containing provider and network fees.\n * @returns Combined on-ramp provider fee.\n */\nexport function getRampsProviderFiatFee(fiatQuote: RampsQuote): BigNumber {\n return getSafeFee(fiatQuote.quote.providerFee).plus(\n getSafeFee(fiatQuote.quote.networkFee),\n );\n}\n\n/**\n * MetaMask's partner fee for a ramps quote.\n *\n * The ramps API reports it as `extraFee`, disjoint from `providerFee` and\n * `networkFee` (the three sum to `totalFees`). Reading it from the quote is\n * what lets the fee vary per quote, including the zero partner fee charged on\n * mUSD.\n *\n * `extraFee` needs a fallback because the ramps backend coerces a missing\n * partner fee to `0`, making an absent field indistinguishable from a genuine\n * zero. That matters more than a display glitch: `fees.metaMask` is an addend\n * of `totals.total`, and the client submits `total - providerFiat` as the\n * amount to buy, so silently reading `0` would undercharge. When the quote\n * also reports `totalFees`, recover the partner fee as the remainder instead.\n *\n * @param fiatQuote - The ramps quote to read fees from.\n * @returns MetaMask's partner fee, or zero when the quote reports none.\n */\nexport function getRampsMetaMaskFee(fiatQuote: RampsQuote): BigNumber {\n const extraFee = getSafeFee(fiatQuote.quote.extraFee);\n\n if (extraFee.isGreaterThan(0)) {\n return extraFee;\n }\n\n const { totalFees } = fiatQuote.quote;\n\n if (totalFees === undefined) {\n return extraFee;\n }\n\n const remainder = getSafeFee(totalFees).minus(\n getRampsProviderFiatFee(fiatQuote),\n );\n\n if (remainder.isGreaterThan(0)) {\n log('Recovered MetaMask fee from quote total fees', {\n extraFee: extraFee.toString(10),\n recovered: remainder.toString(10),\n });\n return remainder;\n }\n\n return extraFee;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"utils.mjs","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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/transaction-pay-controller",
|
|
3
|
-
"version": "27.0.0-preview-
|
|
3
|
+
"version": "27.0.0-preview-c61613ed2",
|
|
4
4
|
"description": "Manages alternate payment strategies to provide required funds for transactions in MetaMask",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
"@metamask/messenger": "^2.0.0",
|
|
69
69
|
"@metamask/metamask-eth-abis": "^3.1.1",
|
|
70
70
|
"@metamask/network-controller": "^36.0.0",
|
|
71
|
-
"@metamask/ramps-controller": "^20.
|
|
72
|
-
"@metamask/remote-feature-flag-controller": "^6.
|
|
71
|
+
"@metamask/ramps-controller": "^20.2.0",
|
|
72
|
+
"@metamask/remote-feature-flag-controller": "^6.1.0",
|
|
73
73
|
"@metamask/sentinel-api-service": "^1.0.1",
|
|
74
74
|
"@metamask/transaction-controller": "^69.6.1",
|
|
75
75
|
"@metamask/utils": "^11.11.0",
|