@metamask/transaction-pay-controller 23.8.0 → 23.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/TransactionPayController-method-action-types.cjs.map +1 -1
  3. package/dist/TransactionPayController-method-action-types.d.cts +12 -1
  4. package/dist/TransactionPayController-method-action-types.d.cts.map +1 -1
  5. package/dist/TransactionPayController-method-action-types.d.mts +12 -1
  6. package/dist/TransactionPayController-method-action-types.d.mts.map +1 -1
  7. package/dist/TransactionPayController-method-action-types.mjs.map +1 -1
  8. package/dist/TransactionPayController.cjs +16 -3
  9. package/dist/TransactionPayController.cjs.map +1 -1
  10. package/dist/TransactionPayController.d.cts +10 -2
  11. package/dist/TransactionPayController.d.cts.map +1 -1
  12. package/dist/TransactionPayController.d.mts +10 -2
  13. package/dist/TransactionPayController.d.mts.map +1 -1
  14. package/dist/TransactionPayController.mjs +16 -3
  15. package/dist/TransactionPayController.mjs.map +1 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +2 -2
  18. package/dist/index.d.cts.map +1 -1
  19. package/dist/index.d.mts +2 -2
  20. package/dist/index.d.mts.map +1 -1
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/strategy/fiat/constants.cjs +1 -3
  23. package/dist/strategy/fiat/constants.cjs.map +1 -1
  24. package/dist/strategy/fiat/constants.d.cts +0 -2
  25. package/dist/strategy/fiat/constants.d.cts.map +1 -1
  26. package/dist/strategy/fiat/constants.d.mts +0 -2
  27. package/dist/strategy/fiat/constants.d.mts.map +1 -1
  28. package/dist/strategy/fiat/constants.mjs +0 -2
  29. package/dist/strategy/fiat/constants.mjs.map +1 -1
  30. package/dist/strategy/fiat/fiat-direct-musd.cjs +246 -0
  31. package/dist/strategy/fiat/fiat-direct-musd.cjs.map +1 -0
  32. package/dist/strategy/fiat/fiat-direct-musd.d.cts +47 -0
  33. package/dist/strategy/fiat/fiat-direct-musd.d.cts.map +1 -0
  34. package/dist/strategy/fiat/fiat-direct-musd.d.mts +47 -0
  35. package/dist/strategy/fiat/fiat-direct-musd.d.mts.map +1 -0
  36. package/dist/strategy/fiat/fiat-direct-musd.mjs +240 -0
  37. package/dist/strategy/fiat/fiat-direct-musd.mjs.map +1 -0
  38. package/dist/strategy/fiat/fiat-quotes.cjs +27 -79
  39. package/dist/strategy/fiat/fiat-quotes.cjs.map +1 -1
  40. package/dist/strategy/fiat/fiat-quotes.d.cts +2 -3
  41. package/dist/strategy/fiat/fiat-quotes.d.cts.map +1 -1
  42. package/dist/strategy/fiat/fiat-quotes.d.mts +2 -3
  43. package/dist/strategy/fiat/fiat-quotes.d.mts.map +1 -1
  44. package/dist/strategy/fiat/fiat-quotes.mjs +28 -80
  45. package/dist/strategy/fiat/fiat-quotes.mjs.map +1 -1
  46. package/dist/strategy/fiat/fiat-submit-simple.cjs +3 -0
  47. package/dist/strategy/fiat/fiat-submit-simple.cjs.map +1 -1
  48. package/dist/strategy/fiat/fiat-submit-simple.d.cts.map +1 -1
  49. package/dist/strategy/fiat/fiat-submit-simple.d.mts.map +1 -1
  50. package/dist/strategy/fiat/fiat-submit-simple.mjs +3 -0
  51. package/dist/strategy/fiat/fiat-submit-simple.mjs.map +1 -1
  52. package/dist/strategy/fiat/fiat-submit-with-transaction-data.cjs +5 -2
  53. package/dist/strategy/fiat/fiat-submit-with-transaction-data.cjs.map +1 -1
  54. package/dist/strategy/fiat/fiat-submit-with-transaction-data.d.cts.map +1 -1
  55. package/dist/strategy/fiat/fiat-submit-with-transaction-data.d.mts.map +1 -1
  56. package/dist/strategy/fiat/fiat-submit-with-transaction-data.mjs +5 -2
  57. package/dist/strategy/fiat/fiat-submit-with-transaction-data.mjs.map +1 -1
  58. package/dist/strategy/fiat/fiat-submit.cjs +57 -35
  59. package/dist/strategy/fiat/fiat-submit.cjs.map +1 -1
  60. package/dist/strategy/fiat/fiat-submit.d.cts.map +1 -1
  61. package/dist/strategy/fiat/fiat-submit.d.mts.map +1 -1
  62. package/dist/strategy/fiat/fiat-submit.mjs +57 -35
  63. package/dist/strategy/fiat/fiat-submit.mjs.map +1 -1
  64. package/dist/strategy/fiat/fiat-test-funding.cjs +166 -0
  65. package/dist/strategy/fiat/fiat-test-funding.cjs.map +1 -0
  66. package/dist/strategy/fiat/fiat-test-funding.d.cts +21 -0
  67. package/dist/strategy/fiat/fiat-test-funding.d.cts.map +1 -0
  68. package/dist/strategy/fiat/fiat-test-funding.d.mts +21 -0
  69. package/dist/strategy/fiat/fiat-test-funding.d.mts.map +1 -0
  70. package/dist/strategy/fiat/fiat-test-funding.mjs +162 -0
  71. package/dist/strategy/fiat/fiat-test-funding.mjs.map +1 -0
  72. package/dist/strategy/fiat/types.cjs.map +1 -1
  73. package/dist/strategy/fiat/types.d.cts +1 -1
  74. package/dist/strategy/fiat/types.d.cts.map +1 -1
  75. package/dist/strategy/fiat/types.d.mts +1 -1
  76. package/dist/strategy/fiat/types.d.mts.map +1 -1
  77. package/dist/strategy/fiat/types.mjs.map +1 -1
  78. package/dist/strategy/fiat/utils.cjs +33 -1
  79. package/dist/strategy/fiat/utils.cjs.map +1 -1
  80. package/dist/strategy/fiat/utils.d.cts +21 -1
  81. package/dist/strategy/fiat/utils.d.cts.map +1 -1
  82. package/dist/strategy/fiat/utils.d.mts +21 -1
  83. package/dist/strategy/fiat/utils.d.mts.map +1 -1
  84. package/dist/strategy/fiat/utils.mjs +33 -2
  85. package/dist/strategy/fiat/utils.mjs.map +1 -1
  86. package/dist/tests/messenger-mock.cjs +3 -0
  87. package/dist/tests/messenger-mock.cjs.map +1 -1
  88. package/dist/tests/messenger-mock.d.cts +1 -0
  89. package/dist/tests/messenger-mock.d.cts.map +1 -1
  90. package/dist/tests/messenger-mock.d.mts +1 -0
  91. package/dist/tests/messenger-mock.d.mts.map +1 -1
  92. package/dist/tests/messenger-mock.mjs +3 -0
  93. package/dist/tests/messenger-mock.mjs.map +1 -1
  94. package/dist/types.cjs.map +1 -1
  95. package/dist/types.d.cts +11 -0
  96. package/dist/types.d.cts.map +1 -1
  97. package/dist/types.d.mts +11 -0
  98. package/dist/types.d.mts.map +1 -1
  99. package/dist/types.mjs.map +1 -1
  100. package/dist/utils/feature-flags.cjs +7 -1
  101. package/dist/utils/feature-flags.cjs.map +1 -1
  102. package/dist/utils/feature-flags.d.cts +1 -0
  103. package/dist/utils/feature-flags.d.cts.map +1 -1
  104. package/dist/utils/feature-flags.d.mts +1 -0
  105. package/dist/utils/feature-flags.d.mts.map +1 -1
  106. package/dist/utils/feature-flags.mjs +5 -0
  107. package/dist/utils/feature-flags.mjs.map +1 -1
  108. package/dist/utils/quotes.cjs +6 -4
  109. package/dist/utils/quotes.cjs.map +1 -1
  110. package/dist/utils/quotes.d.cts.map +1 -1
  111. package/dist/utils/quotes.d.mts.map +1 -1
  112. package/dist/utils/quotes.mjs +6 -4
  113. package/dist/utils/quotes.mjs.map +1 -1
  114. package/package.json +2 -2
@@ -8,8 +8,10 @@ const feature_flags_1 = require("../../utils/feature-flags.cjs");
8
8
  const token_1 = require("../../utils/token.cjs");
9
9
  const transaction_1 = require("../../utils/transaction.cjs");
10
10
  const constants_1 = require("./constants.cjs");
11
+ const fiat_direct_musd_1 = require("./fiat-direct-musd.cjs");
11
12
  const fiat_submit_simple_1 = require("./fiat-submit-simple.cjs");
12
13
  const fiat_submit_with_transaction_data_1 = require("./fiat-submit-with-transaction-data.cjs");
14
+ const fiat_test_funding_1 = require("./fiat-test-funding.cjs");
13
15
  const utils_2 = require("./utils.cjs");
14
16
  const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'fiat-submit');
15
17
  const TERMINAL_FAILURE_STATUSES = [
@@ -60,13 +62,25 @@ async function submitFiatQuotes(request) {
60
62
  providerCode,
61
63
  transactionId,
62
64
  });
63
- const order = await waitForOrderCompletion({
64
- messenger,
65
- orderCode: orderId,
66
- providerCode,
67
- transactionId,
68
- walletAddress,
69
- });
65
+ const fiatQuote = request.quotes[0];
66
+ if (!fiatQuote) {
67
+ throw new Error('Missing fiat quote for relay submission');
68
+ }
69
+ const fiatOptions = getFiatOptions(messenger);
70
+ const order = fiatOptions?.testFundingSource
71
+ ? await (0, fiat_test_funding_1.fundFiatOrderFromTestSource)({
72
+ fiat: fiatOptions,
73
+ messenger,
74
+ quote: fiatQuote,
75
+ transaction,
76
+ })
77
+ : await waitForOrderCompletion({
78
+ messenger,
79
+ orderCode: orderId,
80
+ providerCode,
81
+ transactionId,
82
+ walletAddress,
83
+ });
70
84
  log('Fiat order completed', {
71
85
  cryptoAmount: order.cryptoAmount,
72
86
  orderId,
@@ -75,6 +89,15 @@ async function submitFiatQuotes(request) {
75
89
  return await submitRelayAfterFiatCompletion({ order, request });
76
90
  }
77
91
  exports.submitFiatQuotes = submitFiatQuotes;
92
+ function getFiatOptions(messenger) {
93
+ try {
94
+ return messenger.call('TransactionPayController:getFiatOptions');
95
+ }
96
+ catch (error) {
97
+ log('Failed to retrieve fiat options', error);
98
+ return undefined;
99
+ }
100
+ }
78
101
  /**
79
102
  * Validates that the completed order's crypto asset matches the expected fiat asset.
80
103
  *
@@ -152,31 +175,45 @@ async function waitForOrderCompletion({ messenger, orderCode, providerCode, tran
152
175
  async function submitRelayAfterFiatCompletion({ order, request, }) {
153
176
  const { messenger, quotes, transaction } = request;
154
177
  const transactionId = transaction.id;
155
- if (!quotes.length) {
156
- throw new Error('Missing fiat quote for relay submission');
157
- }
158
178
  if (quotes.length > 1) {
159
179
  throw new Error('Multiple fiat quotes are not supported for submission');
160
180
  }
161
- const isDirectMusd = isDirectMusdToMoneyAccountQuote(quotes);
162
- const fiatAsset = isDirectMusd
163
- ? constants_1.MUSD_MONAD_FIAT_ASSET
164
- : (0, utils_2.deriveFiatAssetForFiatPayment)(transaction, messenger);
181
+ const fiatQuote = quotes[0];
182
+ const isDirectMusd = (0, fiat_direct_musd_1.isDirectMusdMoneyAccountQuote)(fiatQuote);
183
+ if (isDirectMusd) {
184
+ validateOrderAsset({
185
+ expectedAsset: constants_1.MUSD_MONAD_FIAT_ASSET,
186
+ orderCrypto: order.cryptoCurrency,
187
+ transactionId,
188
+ });
189
+ const sourceAmountRaw = await (0, utils_2.resolveSourceAmountRaw)({
190
+ messenger,
191
+ order,
192
+ fiatAsset: constants_1.MUSD_MONAD_FIAT_ASSET,
193
+ walletAddress: transaction.txParams.from,
194
+ });
195
+ return await (0, fiat_direct_musd_1.submitDirectMusdVaultDeposit)({
196
+ request,
197
+ sourceAmountRaw,
198
+ transaction,
199
+ });
200
+ }
201
+ const fiatAsset = (0, utils_2.deriveFiatAssetForFiatPayment)(transaction, messenger);
165
202
  validateOrderAsset({
166
203
  expectedAsset: fiatAsset,
167
204
  orderCrypto: order.cryptoCurrency,
168
205
  transactionId,
169
206
  });
170
- const baseRequest = quotes[0].request;
171
- const sourceAmountWalletAddress = isDirectMusd
172
- ? transaction.txParams.from
173
- : baseRequest.from;
207
+ const baseRequest = fiatQuote.request;
174
208
  const sourceAmountRaw = await (0, utils_2.resolveSourceAmountRaw)({
175
209
  messenger,
176
210
  order,
177
211
  fiatAsset,
178
- walletAddress: sourceAmountWalletAddress,
212
+ walletAddress: baseRequest.from,
179
213
  });
214
+ if (!fiatQuote.original.relayQuote) {
215
+ throw new Error('Missing Relay quote for fiat submission');
216
+ }
180
217
  const hasNestedCalldata = (transaction.nestedTransactions?.length ?? 0) >= 2;
181
218
  // Transactions with nested calldata (e.g. moneyAccountDeposit with
182
219
  // approve + deposit) need a three-phase flow: discovery quote to learn
@@ -198,23 +235,8 @@ async function submitRelayAfterFiatCompletion({ order, request, }) {
198
235
  transaction,
199
236
  });
200
237
  }
201
- /**
202
- * Detects whether the given quotes originated from the direct mUSD-to-
203
- * Money-Account flow by inspecting the stored quote request's source
204
- * chain and token. This is more reliable than re-checking the feature
205
- * flag, which could change between quote and submit.
206
- *
207
- * @param quotes - The fiat quotes to inspect.
208
- * @returns `true` if the first quote targets mUSD on Monad as its source.
209
- */
210
- function isDirectMusdToMoneyAccountQuote(quotes) {
211
- const request = quotes[0]?.request;
212
- return (request?.sourceChainId === constants_1.MUSD_MONAD_FIAT_ASSET.chainId &&
213
- request?.sourceTokenAddress.toLowerCase() ===
214
- constants_1.MUSD_MONAD_FIAT_ASSET.address.toLowerCase());
215
- }
216
238
  function getWalletAddress({ quotes, transaction, accountOverride, }) {
217
- const address = isDirectMusdToMoneyAccountQuote(quotes)
239
+ const address = (0, fiat_direct_musd_1.isDirectMusdMoneyAccountQuote)(quotes[0])
218
240
  ? transaction.txParams.from
219
241
  : (accountOverride ?? transaction.txParams.from);
220
242
  if (!address) {
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-submit.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RampsOrder,\n RampsOrderCryptoCurrency,\n} from '@metamask/ramps-controller';\nimport { RampsOrderStatus } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n TransactionPayControllerMessenger,\n} from '../../types';\nimport {\n getFiatOrderPollIntervalMs,\n getFiatOrderPollTimeoutMs,\n} from '../../utils/feature-flags';\nimport { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport type { TransactionPayFiatAsset } from './constants';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants';\nimport { submitSimpleRelay } from './fiat-submit-simple';\nimport { submitWithTransactionData } from './fiat-submit-with-transaction-data';\nimport type { FiatQuote } from './types';\nimport {\n deriveFiatAssetForFiatPayment,\n extractProviderCode,\n resolveSourceAmountRaw,\n} from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst TERMINAL_FAILURE_STATUSES: RampsOrderStatus[] = [\n RampsOrderStatus.Cancelled,\n RampsOrderStatus.Failed,\n RampsOrderStatus.IdExpired,\n];\n\n/**\n * Submits fiat strategy quotes by polling the on-ramp order until completion,\n * then re-quoting and submitting the relay leg with the settled crypto amount.\n *\n * @param request - Strategy execute request containing fiat quotes, messenger, and transaction metadata.\n * @param request.messenger - Controller messenger for cross-controller calls.\n * @param request.quotes - Fiat quotes to execute (exactly one expected).\n * @param request.transaction - Original transaction metadata.\n * @param request.isSmartTransaction - Callback to check smart transaction eligibility.\n * @returns An object containing the relay transaction hash if available.\n */\nexport async function submitFiatQuotes(\n request: PayStrategyExecuteRequest<FiatQuote>,\n): ReturnType<PayStrategy<FiatQuote>['execute']> {\n const { messenger, transaction } = request;\n const transactionId = transaction.id;\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transactionId];\n\n const walletAddress = getWalletAddress({\n quotes: request.quotes,\n transaction,\n accountOverride: transactionData?.accountOverride,\n });\n\n const fiatPayment = transactionData?.fiatPayment;\n const orderId = fiatPayment?.orderId;\n\n if (!orderId) {\n throw new Error('Missing order ID for fiat submission');\n }\n\n const providerCode = extractProviderCode(fiatPayment?.rampsQuote?.provider);\n\n if (!providerCode) {\n throw new Error('Missing provider code for fiat submission');\n }\n\n updateTransaction(\n {\n transactionId,\n messenger,\n note: 'Persist fiat order metadata',\n },\n (tx) => {\n tx.metamaskPay ??= {};\n tx.metamaskPay.fiat = { orderId, provider: providerCode };\n },\n );\n\n log('Starting fiat order polling', {\n orderId,\n providerCode,\n transactionId,\n });\n\n const order = await waitForOrderCompletion({\n messenger,\n orderCode: orderId,\n providerCode,\n transactionId,\n walletAddress,\n });\n\n log('Fiat order completed', {\n cryptoAmount: order.cryptoAmount,\n orderId,\n transactionId,\n });\n\n return await submitRelayAfterFiatCompletion({ order, request });\n}\n\n/**\n * Validates that the 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 */\nfunction 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 `Fiat order asset mismatch for transaction ${transactionId}: ` +\n `expected ${expectedAssetId}, got ${orderAssetId}`,\n );\n }\n\n if (orderChainId && orderChainId !== expectedChainId) {\n throw new Error(\n `Fiat order chain mismatch for transaction ${transactionId}: ` +\n `expected ${expectedChainId}, got ${orderChainId}`,\n );\n }\n}\n\n/**\n * Polls the on-ramp order until it reaches a terminal status.\n *\n * @param options - The polling options.\n * @param options.messenger - Controller messenger for calling `RampsController:getOrder`.\n * @param options.orderCode - The order identifier within the provider.\n * @param options.providerCode - The on-ramp provider code (e.g. \"transak\").\n * @param options.transactionId - Transaction ID for logging.\n * @param options.walletAddress - Wallet address associated with the order.\n * @returns The completed order data.\n */\nasync function waitForOrderCompletion({\n messenger,\n orderCode,\n providerCode,\n transactionId,\n walletAddress,\n}: {\n messenger: TransactionPayControllerMessenger;\n orderCode: string;\n providerCode: string;\n transactionId: string;\n walletAddress: string;\n}): Promise<RampsOrder> {\n const pollIntervalMs = getFiatOrderPollIntervalMs(messenger);\n const pollTimeoutMs = getFiatOrderPollTimeoutMs(messenger);\n const startTime = Date.now();\n let lastStatus: string | undefined;\n\n while (true) {\n let order: RampsOrder | undefined;\n\n try {\n order = await messenger.call(\n 'RampsController:getOrder',\n providerCode,\n orderCode,\n walletAddress,\n );\n } catch (error) {\n log('Order polling network error', error);\n }\n\n if (order) {\n lastStatus = order.status;\n\n log('Polled fiat order', {\n orderStatus: order.status,\n providerCode,\n transactionId,\n });\n\n if (order.status === RampsOrderStatus.Completed) {\n return order;\n }\n\n if (TERMINAL_FAILURE_STATUSES.includes(order.status)) {\n throw new Error(`Fiat order ${order.status.toLowerCase()}`);\n }\n }\n\n if (Date.now() - startTime >= pollTimeoutMs) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));\n }\n}\n\n/**\n * Re-quotes and submits the relay leg using the settled amount from a completed fiat order.\n *\n * @param options - The submission options.\n * @param options.order - The completed on-ramp order containing the settled crypto amount.\n * @param options.request - The original fiat strategy execute request.\n * @returns An object containing the relay transaction hash if available.\n */\nasync function submitRelayAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, quotes, transaction } = request;\n const transactionId = transaction.id;\n\n if (!quotes.length) {\n throw new Error('Missing fiat quote for relay submission');\n }\n\n if (quotes.length > 1) {\n throw new Error('Multiple fiat quotes are not supported for submission');\n }\n\n const isDirectMusd = isDirectMusdToMoneyAccountQuote(quotes);\n const fiatAsset = isDirectMusd\n ? MUSD_MONAD_FIAT_ASSET\n : deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const baseRequest = quotes[0].request;\n\n const sourceAmountWalletAddress = isDirectMusd\n ? (transaction.txParams.from as Hex)\n : baseRequest.from;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress: sourceAmountWalletAddress,\n });\n\n const hasNestedCalldata = (transaction.nestedTransactions?.length ?? 0) >= 2;\n\n // Transactions with nested calldata (e.g. moneyAccountDeposit with\n // approve + deposit) need a three-phase flow: discovery quote to learn\n // the target amount, calldata re-encoding, then a delegation quote.\n // Simple deposits (Perps, Predict) skip straight to a single EXACT_INPUT\n // relay quote — cheaper fees, no leftover dust, one fewer request.\n if (hasNestedCalldata) {\n return await submitWithTransactionData({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n }\n\n return await submitSimpleRelay({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n}\n\n/**\n * Detects whether the given quotes originated from the direct mUSD-to-\n * Money-Account flow by inspecting the stored quote request's source\n * chain and token. This is more reliable than re-checking the feature\n * flag, which could change between quote and submit.\n *\n * @param quotes - The fiat quotes to inspect.\n * @returns `true` if the first quote targets mUSD on Monad as its source.\n */\nfunction isDirectMusdToMoneyAccountQuote(\n quotes: PayStrategyExecuteRequest<FiatQuote>['quotes'],\n): boolean {\n const request = quotes[0]?.request;\n return (\n request?.sourceChainId === MUSD_MONAD_FIAT_ASSET.chainId &&\n request?.sourceTokenAddress.toLowerCase() ===\n MUSD_MONAD_FIAT_ASSET.address.toLowerCase()\n );\n}\n\nfunction getWalletAddress({\n quotes,\n transaction,\n accountOverride,\n}: {\n quotes: PayStrategyExecuteRequest<FiatQuote>['quotes'];\n transaction: PayStrategyExecuteRequest<FiatQuote>['transaction'];\n accountOverride: Hex | undefined;\n}): Hex {\n const address = isDirectMusdToMoneyAccountQuote(quotes)\n ? transaction.txParams.from\n : (accountOverride ?? transaction.txParams.from);\n\n if (!address) {\n throw new Error('Missing wallet address for fiat submission');\n }\n\n return address as Hex;\n}\n"]}
1
+ {"version":3,"file":"fiat-submit.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RampsOrder,\n RampsOrderCryptoCurrency,\n} from '@metamask/ramps-controller';\nimport { RampsOrderStatus } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n TransactionPayFiatOptions,\n TransactionPayControllerMessenger,\n} from '../../types';\nimport {\n getFiatOrderPollIntervalMs,\n getFiatOrderPollTimeoutMs,\n} from '../../utils/feature-flags';\nimport { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport type { TransactionPayFiatAsset } from './constants';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants';\nimport {\n isDirectMusdMoneyAccountQuote,\n submitDirectMusdVaultDeposit,\n} from './fiat-direct-musd';\nimport { submitSimpleRelay } from './fiat-submit-simple';\nimport { submitWithTransactionData } from './fiat-submit-with-transaction-data';\nimport { fundFiatOrderFromTestSource } from './fiat-test-funding';\nimport type { FiatQuote } from './types';\nimport {\n deriveFiatAssetForFiatPayment,\n extractProviderCode,\n resolveSourceAmountRaw,\n} from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst TERMINAL_FAILURE_STATUSES: RampsOrderStatus[] = [\n RampsOrderStatus.Cancelled,\n RampsOrderStatus.Failed,\n RampsOrderStatus.IdExpired,\n];\n\n/**\n * Submits fiat strategy quotes by polling the on-ramp order until completion,\n * then re-quoting and submitting the relay leg with the settled crypto amount.\n *\n * @param request - Strategy execute request containing fiat quotes, messenger, and transaction metadata.\n * @param request.messenger - Controller messenger for cross-controller calls.\n * @param request.quotes - Fiat quotes to execute (exactly one expected).\n * @param request.transaction - Original transaction metadata.\n * @param request.isSmartTransaction - Callback to check smart transaction eligibility.\n * @returns An object containing the relay transaction hash if available.\n */\nexport async function submitFiatQuotes(\n request: PayStrategyExecuteRequest<FiatQuote>,\n): ReturnType<PayStrategy<FiatQuote>['execute']> {\n const { messenger, transaction } = request;\n const transactionId = transaction.id;\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transactionId];\n\n const walletAddress = getWalletAddress({\n quotes: request.quotes,\n transaction,\n accountOverride: transactionData?.accountOverride,\n });\n\n const fiatPayment = transactionData?.fiatPayment;\n const orderId = fiatPayment?.orderId;\n\n if (!orderId) {\n throw new Error('Missing order ID for fiat submission');\n }\n\n const providerCode = extractProviderCode(fiatPayment?.rampsQuote?.provider);\n\n if (!providerCode) {\n throw new Error('Missing provider code for fiat submission');\n }\n\n updateTransaction(\n {\n transactionId,\n messenger,\n note: 'Persist fiat order metadata',\n },\n (tx) => {\n tx.metamaskPay ??= {};\n tx.metamaskPay.fiat = { orderId, provider: providerCode };\n },\n );\n\n log('Starting fiat order polling', {\n orderId,\n providerCode,\n transactionId,\n });\n\n const fiatQuote = request.quotes[0];\n\n if (!fiatQuote) {\n throw new Error('Missing fiat quote for relay submission');\n }\n\n const fiatOptions = getFiatOptions(messenger);\n\n const order = fiatOptions?.testFundingSource\n ? await fundFiatOrderFromTestSource({\n fiat: fiatOptions,\n messenger,\n quote: fiatQuote,\n transaction,\n })\n : await waitForOrderCompletion({\n messenger,\n orderCode: orderId,\n providerCode,\n transactionId,\n walletAddress,\n });\n\n log('Fiat order completed', {\n cryptoAmount: order.cryptoAmount,\n orderId,\n transactionId,\n });\n\n return await submitRelayAfterFiatCompletion({ order, request });\n}\n\nfunction getFiatOptions(\n messenger: TransactionPayControllerMessenger,\n): TransactionPayFiatOptions | undefined {\n try {\n return messenger.call('TransactionPayController:getFiatOptions');\n } catch (error) {\n log('Failed to retrieve fiat options', error);\n return undefined;\n }\n}\n\n/**\n * Validates that the 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 */\nfunction 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 `Fiat order asset mismatch for transaction ${transactionId}: ` +\n `expected ${expectedAssetId}, got ${orderAssetId}`,\n );\n }\n\n if (orderChainId && orderChainId !== expectedChainId) {\n throw new Error(\n `Fiat order chain mismatch for transaction ${transactionId}: ` +\n `expected ${expectedChainId}, got ${orderChainId}`,\n );\n }\n}\n\n/**\n * Polls the on-ramp order until it reaches a terminal status.\n *\n * @param options - The polling options.\n * @param options.messenger - Controller messenger for calling `RampsController:getOrder`.\n * @param options.orderCode - The order identifier within the provider.\n * @param options.providerCode - The on-ramp provider code (e.g. \"transak\").\n * @param options.transactionId - Transaction ID for logging.\n * @param options.walletAddress - Wallet address associated with the order.\n * @returns The completed order data.\n */\nasync function waitForOrderCompletion({\n messenger,\n orderCode,\n providerCode,\n transactionId,\n walletAddress,\n}: {\n messenger: TransactionPayControllerMessenger;\n orderCode: string;\n providerCode: string;\n transactionId: string;\n walletAddress: string;\n}): Promise<RampsOrder> {\n const pollIntervalMs = getFiatOrderPollIntervalMs(messenger);\n const pollTimeoutMs = getFiatOrderPollTimeoutMs(messenger);\n const startTime = Date.now();\n let lastStatus: string | undefined;\n\n while (true) {\n let order: RampsOrder | undefined;\n\n try {\n order = await messenger.call(\n 'RampsController:getOrder',\n providerCode,\n orderCode,\n walletAddress,\n );\n } catch (error) {\n log('Order polling network error', error);\n }\n\n if (order) {\n lastStatus = order.status;\n\n log('Polled fiat order', {\n orderStatus: order.status,\n providerCode,\n transactionId,\n });\n\n if (order.status === RampsOrderStatus.Completed) {\n return order;\n }\n\n if (TERMINAL_FAILURE_STATUSES.includes(order.status)) {\n throw new Error(`Fiat order ${order.status.toLowerCase()}`);\n }\n }\n\n if (Date.now() - startTime >= pollTimeoutMs) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));\n }\n}\n\n/**\n * Re-quotes and submits the relay leg using the settled amount from a completed fiat order.\n *\n * @param options - The submission options.\n * @param options.order - The completed on-ramp order containing the settled crypto amount.\n * @param options.request - The original fiat strategy execute request.\n * @returns An object containing the relay transaction hash if available.\n */\nasync function submitRelayAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, quotes, transaction } = request;\n const transactionId = transaction.id;\n\n if (quotes.length > 1) {\n throw new Error('Multiple fiat quotes are not supported for submission');\n }\n\n const fiatQuote = quotes[0];\n const isDirectMusd = isDirectMusdMoneyAccountQuote(fiatQuote);\n\n if (isDirectMusd) {\n validateOrderAsset({\n expectedAsset: MUSD_MONAD_FIAT_ASSET,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n walletAddress: transaction.txParams.from as Hex,\n });\n\n return await submitDirectMusdVaultDeposit({\n request,\n sourceAmountRaw,\n transaction,\n });\n }\n\n const fiatAsset = deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const baseRequest = fiatQuote.request;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress: baseRequest.from,\n });\n\n if (!fiatQuote.original.relayQuote) {\n throw new Error('Missing Relay quote for fiat submission');\n }\n\n const hasNestedCalldata = (transaction.nestedTransactions?.length ?? 0) >= 2;\n\n // Transactions with nested calldata (e.g. moneyAccountDeposit with\n // approve + deposit) need a three-phase flow: discovery quote to learn\n // the target amount, calldata re-encoding, then a delegation quote.\n // Simple deposits (Perps, Predict) skip straight to a single EXACT_INPUT\n // relay quote — cheaper fees, no leftover dust, one fewer request.\n if (hasNestedCalldata) {\n return await submitWithTransactionData({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n }\n\n return await submitSimpleRelay({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n}\n\nfunction getWalletAddress({\n quotes,\n transaction,\n accountOverride,\n}: {\n quotes: PayStrategyExecuteRequest<FiatQuote>['quotes'];\n transaction: PayStrategyExecuteRequest<FiatQuote>['transaction'];\n accountOverride: Hex | undefined;\n}): Hex {\n const address = isDirectMusdMoneyAccountQuote(quotes[0])\n ? transaction.txParams.from\n : (accountOverride ?? transaction.txParams.from);\n\n if (!address) {\n throw new Error('Missing wallet address for fiat submission');\n }\n\n return address as Hex;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-submit.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EAE1B,wBAAoB;AAWrB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAgB;AAezC;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,GAC5C,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CA0D/C"}
1
+ {"version":3,"file":"fiat-submit.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EAG1B,wBAAoB;AAgBrB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAgB;AAezC;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,GAC5C,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAyE/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-submit.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EAE1B,wBAAoB;AAWrB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAgB;AAezC;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,GAC5C,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CA0D/C"}
1
+ {"version":3,"file":"fiat-submit.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EAG1B,wBAAoB;AAgBrB,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAgB;AAezC;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,GAC5C,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAyE/C"}
@@ -5,8 +5,10 @@ import { getFiatOrderPollIntervalMs, getFiatOrderPollTimeoutMs } from "../../uti
5
5
  import { buildCaipAssetType } from "../../utils/token.mjs";
6
6
  import { updateTransaction } from "../../utils/transaction.mjs";
7
7
  import { MUSD_MONAD_FIAT_ASSET } from "./constants.mjs";
8
+ import { isDirectMusdMoneyAccountQuote, submitDirectMusdVaultDeposit } from "./fiat-direct-musd.mjs";
8
9
  import { submitSimpleRelay } from "./fiat-submit-simple.mjs";
9
10
  import { submitWithTransactionData } from "./fiat-submit-with-transaction-data.mjs";
11
+ import { fundFiatOrderFromTestSource } from "./fiat-test-funding.mjs";
10
12
  import { deriveFiatAssetForFiatPayment, extractProviderCode, resolveSourceAmountRaw } from "./utils.mjs";
11
13
  const log = createModuleLogger(projectLogger, 'fiat-submit');
12
14
  const TERMINAL_FAILURE_STATUSES = [
@@ -57,13 +59,25 @@ export async function submitFiatQuotes(request) {
57
59
  providerCode,
58
60
  transactionId,
59
61
  });
60
- const order = await waitForOrderCompletion({
61
- messenger,
62
- orderCode: orderId,
63
- providerCode,
64
- transactionId,
65
- walletAddress,
66
- });
62
+ const fiatQuote = request.quotes[0];
63
+ if (!fiatQuote) {
64
+ throw new Error('Missing fiat quote for relay submission');
65
+ }
66
+ const fiatOptions = getFiatOptions(messenger);
67
+ const order = fiatOptions?.testFundingSource
68
+ ? await fundFiatOrderFromTestSource({
69
+ fiat: fiatOptions,
70
+ messenger,
71
+ quote: fiatQuote,
72
+ transaction,
73
+ })
74
+ : await waitForOrderCompletion({
75
+ messenger,
76
+ orderCode: orderId,
77
+ providerCode,
78
+ transactionId,
79
+ walletAddress,
80
+ });
67
81
  log('Fiat order completed', {
68
82
  cryptoAmount: order.cryptoAmount,
69
83
  orderId,
@@ -71,6 +85,15 @@ export async function submitFiatQuotes(request) {
71
85
  });
72
86
  return await submitRelayAfterFiatCompletion({ order, request });
73
87
  }
88
+ function getFiatOptions(messenger) {
89
+ try {
90
+ return messenger.call('TransactionPayController:getFiatOptions');
91
+ }
92
+ catch (error) {
93
+ log('Failed to retrieve fiat options', error);
94
+ return undefined;
95
+ }
96
+ }
74
97
  /**
75
98
  * Validates that the completed order's crypto asset matches the expected fiat asset.
76
99
  *
@@ -148,31 +171,45 @@ async function waitForOrderCompletion({ messenger, orderCode, providerCode, tran
148
171
  async function submitRelayAfterFiatCompletion({ order, request, }) {
149
172
  const { messenger, quotes, transaction } = request;
150
173
  const transactionId = transaction.id;
151
- if (!quotes.length) {
152
- throw new Error('Missing fiat quote for relay submission');
153
- }
154
174
  if (quotes.length > 1) {
155
175
  throw new Error('Multiple fiat quotes are not supported for submission');
156
176
  }
157
- const isDirectMusd = isDirectMusdToMoneyAccountQuote(quotes);
158
- const fiatAsset = isDirectMusd
159
- ? MUSD_MONAD_FIAT_ASSET
160
- : deriveFiatAssetForFiatPayment(transaction, messenger);
177
+ const fiatQuote = quotes[0];
178
+ const isDirectMusd = isDirectMusdMoneyAccountQuote(fiatQuote);
179
+ if (isDirectMusd) {
180
+ validateOrderAsset({
181
+ expectedAsset: MUSD_MONAD_FIAT_ASSET,
182
+ orderCrypto: order.cryptoCurrency,
183
+ transactionId,
184
+ });
185
+ const sourceAmountRaw = await resolveSourceAmountRaw({
186
+ messenger,
187
+ order,
188
+ fiatAsset: MUSD_MONAD_FIAT_ASSET,
189
+ walletAddress: transaction.txParams.from,
190
+ });
191
+ return await submitDirectMusdVaultDeposit({
192
+ request,
193
+ sourceAmountRaw,
194
+ transaction,
195
+ });
196
+ }
197
+ const fiatAsset = deriveFiatAssetForFiatPayment(transaction, messenger);
161
198
  validateOrderAsset({
162
199
  expectedAsset: fiatAsset,
163
200
  orderCrypto: order.cryptoCurrency,
164
201
  transactionId,
165
202
  });
166
- const baseRequest = quotes[0].request;
167
- const sourceAmountWalletAddress = isDirectMusd
168
- ? transaction.txParams.from
169
- : baseRequest.from;
203
+ const baseRequest = fiatQuote.request;
170
204
  const sourceAmountRaw = await resolveSourceAmountRaw({
171
205
  messenger,
172
206
  order,
173
207
  fiatAsset,
174
- walletAddress: sourceAmountWalletAddress,
208
+ walletAddress: baseRequest.from,
175
209
  });
210
+ if (!fiatQuote.original.relayQuote) {
211
+ throw new Error('Missing Relay quote for fiat submission');
212
+ }
176
213
  const hasNestedCalldata = (transaction.nestedTransactions?.length ?? 0) >= 2;
177
214
  // Transactions with nested calldata (e.g. moneyAccountDeposit with
178
215
  // approve + deposit) need a three-phase flow: discovery quote to learn
@@ -194,23 +231,8 @@ async function submitRelayAfterFiatCompletion({ order, request, }) {
194
231
  transaction,
195
232
  });
196
233
  }
197
- /**
198
- * Detects whether the given quotes originated from the direct mUSD-to-
199
- * Money-Account flow by inspecting the stored quote request's source
200
- * chain and token. This is more reliable than re-checking the feature
201
- * flag, which could change between quote and submit.
202
- *
203
- * @param quotes - The fiat quotes to inspect.
204
- * @returns `true` if the first quote targets mUSD on Monad as its source.
205
- */
206
- function isDirectMusdToMoneyAccountQuote(quotes) {
207
- const request = quotes[0]?.request;
208
- return (request?.sourceChainId === MUSD_MONAD_FIAT_ASSET.chainId &&
209
- request?.sourceTokenAddress.toLowerCase() ===
210
- MUSD_MONAD_FIAT_ASSET.address.toLowerCase());
211
- }
212
234
  function getWalletAddress({ quotes, transaction, accountOverride, }) {
213
- const address = isDirectMusdToMoneyAccountQuote(quotes)
235
+ const address = isDirectMusdMoneyAccountQuote(quotes[0])
214
236
  ? transaction.txParams.from
215
237
  : (accountOverride ?? transaction.txParams.from);
216
238
  if (!address) {
@@ -1 +1 @@
1
- {"version":3,"file":"fiat-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RampsOrder,\n RampsOrderCryptoCurrency,\n} from '@metamask/ramps-controller';\nimport { RampsOrderStatus } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n TransactionPayControllerMessenger,\n} from '../../types';\nimport {\n getFiatOrderPollIntervalMs,\n getFiatOrderPollTimeoutMs,\n} from '../../utils/feature-flags';\nimport { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport type { TransactionPayFiatAsset } from './constants';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants';\nimport { submitSimpleRelay } from './fiat-submit-simple';\nimport { submitWithTransactionData } from './fiat-submit-with-transaction-data';\nimport type { FiatQuote } from './types';\nimport {\n deriveFiatAssetForFiatPayment,\n extractProviderCode,\n resolveSourceAmountRaw,\n} from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst TERMINAL_FAILURE_STATUSES: RampsOrderStatus[] = [\n RampsOrderStatus.Cancelled,\n RampsOrderStatus.Failed,\n RampsOrderStatus.IdExpired,\n];\n\n/**\n * Submits fiat strategy quotes by polling the on-ramp order until completion,\n * then re-quoting and submitting the relay leg with the settled crypto amount.\n *\n * @param request - Strategy execute request containing fiat quotes, messenger, and transaction metadata.\n * @param request.messenger - Controller messenger for cross-controller calls.\n * @param request.quotes - Fiat quotes to execute (exactly one expected).\n * @param request.transaction - Original transaction metadata.\n * @param request.isSmartTransaction - Callback to check smart transaction eligibility.\n * @returns An object containing the relay transaction hash if available.\n */\nexport async function submitFiatQuotes(\n request: PayStrategyExecuteRequest<FiatQuote>,\n): ReturnType<PayStrategy<FiatQuote>['execute']> {\n const { messenger, transaction } = request;\n const transactionId = transaction.id;\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transactionId];\n\n const walletAddress = getWalletAddress({\n quotes: request.quotes,\n transaction,\n accountOverride: transactionData?.accountOverride,\n });\n\n const fiatPayment = transactionData?.fiatPayment;\n const orderId = fiatPayment?.orderId;\n\n if (!orderId) {\n throw new Error('Missing order ID for fiat submission');\n }\n\n const providerCode = extractProviderCode(fiatPayment?.rampsQuote?.provider);\n\n if (!providerCode) {\n throw new Error('Missing provider code for fiat submission');\n }\n\n updateTransaction(\n {\n transactionId,\n messenger,\n note: 'Persist fiat order metadata',\n },\n (tx) => {\n tx.metamaskPay ??= {};\n tx.metamaskPay.fiat = { orderId, provider: providerCode };\n },\n );\n\n log('Starting fiat order polling', {\n orderId,\n providerCode,\n transactionId,\n });\n\n const order = await waitForOrderCompletion({\n messenger,\n orderCode: orderId,\n providerCode,\n transactionId,\n walletAddress,\n });\n\n log('Fiat order completed', {\n cryptoAmount: order.cryptoAmount,\n orderId,\n transactionId,\n });\n\n return await submitRelayAfterFiatCompletion({ order, request });\n}\n\n/**\n * Validates that the 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 */\nfunction 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 `Fiat order asset mismatch for transaction ${transactionId}: ` +\n `expected ${expectedAssetId}, got ${orderAssetId}`,\n );\n }\n\n if (orderChainId && orderChainId !== expectedChainId) {\n throw new Error(\n `Fiat order chain mismatch for transaction ${transactionId}: ` +\n `expected ${expectedChainId}, got ${orderChainId}`,\n );\n }\n}\n\n/**\n * Polls the on-ramp order until it reaches a terminal status.\n *\n * @param options - The polling options.\n * @param options.messenger - Controller messenger for calling `RampsController:getOrder`.\n * @param options.orderCode - The order identifier within the provider.\n * @param options.providerCode - The on-ramp provider code (e.g. \"transak\").\n * @param options.transactionId - Transaction ID for logging.\n * @param options.walletAddress - Wallet address associated with the order.\n * @returns The completed order data.\n */\nasync function waitForOrderCompletion({\n messenger,\n orderCode,\n providerCode,\n transactionId,\n walletAddress,\n}: {\n messenger: TransactionPayControllerMessenger;\n orderCode: string;\n providerCode: string;\n transactionId: string;\n walletAddress: string;\n}): Promise<RampsOrder> {\n const pollIntervalMs = getFiatOrderPollIntervalMs(messenger);\n const pollTimeoutMs = getFiatOrderPollTimeoutMs(messenger);\n const startTime = Date.now();\n let lastStatus: string | undefined;\n\n while (true) {\n let order: RampsOrder | undefined;\n\n try {\n order = await messenger.call(\n 'RampsController:getOrder',\n providerCode,\n orderCode,\n walletAddress,\n );\n } catch (error) {\n log('Order polling network error', error);\n }\n\n if (order) {\n lastStatus = order.status;\n\n log('Polled fiat order', {\n orderStatus: order.status,\n providerCode,\n transactionId,\n });\n\n if (order.status === RampsOrderStatus.Completed) {\n return order;\n }\n\n if (TERMINAL_FAILURE_STATUSES.includes(order.status)) {\n throw new Error(`Fiat order ${order.status.toLowerCase()}`);\n }\n }\n\n if (Date.now() - startTime >= pollTimeoutMs) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));\n }\n}\n\n/**\n * Re-quotes and submits the relay leg using the settled amount from a completed fiat order.\n *\n * @param options - The submission options.\n * @param options.order - The completed on-ramp order containing the settled crypto amount.\n * @param options.request - The original fiat strategy execute request.\n * @returns An object containing the relay transaction hash if available.\n */\nasync function submitRelayAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, quotes, transaction } = request;\n const transactionId = transaction.id;\n\n if (!quotes.length) {\n throw new Error('Missing fiat quote for relay submission');\n }\n\n if (quotes.length > 1) {\n throw new Error('Multiple fiat quotes are not supported for submission');\n }\n\n const isDirectMusd = isDirectMusdToMoneyAccountQuote(quotes);\n const fiatAsset = isDirectMusd\n ? MUSD_MONAD_FIAT_ASSET\n : deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const baseRequest = quotes[0].request;\n\n const sourceAmountWalletAddress = isDirectMusd\n ? (transaction.txParams.from as Hex)\n : baseRequest.from;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress: sourceAmountWalletAddress,\n });\n\n const hasNestedCalldata = (transaction.nestedTransactions?.length ?? 0) >= 2;\n\n // Transactions with nested calldata (e.g. moneyAccountDeposit with\n // approve + deposit) need a three-phase flow: discovery quote to learn\n // the target amount, calldata re-encoding, then a delegation quote.\n // Simple deposits (Perps, Predict) skip straight to a single EXACT_INPUT\n // relay quote — cheaper fees, no leftover dust, one fewer request.\n if (hasNestedCalldata) {\n return await submitWithTransactionData({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n }\n\n return await submitSimpleRelay({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n}\n\n/**\n * Detects whether the given quotes originated from the direct mUSD-to-\n * Money-Account flow by inspecting the stored quote request's source\n * chain and token. This is more reliable than re-checking the feature\n * flag, which could change between quote and submit.\n *\n * @param quotes - The fiat quotes to inspect.\n * @returns `true` if the first quote targets mUSD on Monad as its source.\n */\nfunction isDirectMusdToMoneyAccountQuote(\n quotes: PayStrategyExecuteRequest<FiatQuote>['quotes'],\n): boolean {\n const request = quotes[0]?.request;\n return (\n request?.sourceChainId === MUSD_MONAD_FIAT_ASSET.chainId &&\n request?.sourceTokenAddress.toLowerCase() ===\n MUSD_MONAD_FIAT_ASSET.address.toLowerCase()\n );\n}\n\nfunction getWalletAddress({\n quotes,\n transaction,\n accountOverride,\n}: {\n quotes: PayStrategyExecuteRequest<FiatQuote>['quotes'];\n transaction: PayStrategyExecuteRequest<FiatQuote>['transaction'];\n accountOverride: Hex | undefined;\n}): Hex {\n const address = isDirectMusdToMoneyAccountQuote(quotes)\n ? transaction.txParams.from\n : (accountOverride ?? transaction.txParams.from);\n\n if (!address) {\n throw new Error('Missing wallet address for fiat submission');\n }\n\n return address as Hex;\n}\n"]}
1
+ {"version":3,"file":"fiat-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RampsOrder,\n RampsOrderCryptoCurrency,\n} from '@metamask/ramps-controller';\nimport { RampsOrderStatus } from '@metamask/ramps-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n TransactionPayFiatOptions,\n TransactionPayControllerMessenger,\n} from '../../types';\nimport {\n getFiatOrderPollIntervalMs,\n getFiatOrderPollTimeoutMs,\n} from '../../utils/feature-flags';\nimport { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport type { TransactionPayFiatAsset } from './constants';\nimport { MUSD_MONAD_FIAT_ASSET } from './constants';\nimport {\n isDirectMusdMoneyAccountQuote,\n submitDirectMusdVaultDeposit,\n} from './fiat-direct-musd';\nimport { submitSimpleRelay } from './fiat-submit-simple';\nimport { submitWithTransactionData } from './fiat-submit-with-transaction-data';\nimport { fundFiatOrderFromTestSource } from './fiat-test-funding';\nimport type { FiatQuote } from './types';\nimport {\n deriveFiatAssetForFiatPayment,\n extractProviderCode,\n resolveSourceAmountRaw,\n} from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst TERMINAL_FAILURE_STATUSES: RampsOrderStatus[] = [\n RampsOrderStatus.Cancelled,\n RampsOrderStatus.Failed,\n RampsOrderStatus.IdExpired,\n];\n\n/**\n * Submits fiat strategy quotes by polling the on-ramp order until completion,\n * then re-quoting and submitting the relay leg with the settled crypto amount.\n *\n * @param request - Strategy execute request containing fiat quotes, messenger, and transaction metadata.\n * @param request.messenger - Controller messenger for cross-controller calls.\n * @param request.quotes - Fiat quotes to execute (exactly one expected).\n * @param request.transaction - Original transaction metadata.\n * @param request.isSmartTransaction - Callback to check smart transaction eligibility.\n * @returns An object containing the relay transaction hash if available.\n */\nexport async function submitFiatQuotes(\n request: PayStrategyExecuteRequest<FiatQuote>,\n): ReturnType<PayStrategy<FiatQuote>['execute']> {\n const { messenger, transaction } = request;\n const transactionId = transaction.id;\n const state = messenger.call('TransactionPayController:getState');\n const transactionData = state.transactionData[transactionId];\n\n const walletAddress = getWalletAddress({\n quotes: request.quotes,\n transaction,\n accountOverride: transactionData?.accountOverride,\n });\n\n const fiatPayment = transactionData?.fiatPayment;\n const orderId = fiatPayment?.orderId;\n\n if (!orderId) {\n throw new Error('Missing order ID for fiat submission');\n }\n\n const providerCode = extractProviderCode(fiatPayment?.rampsQuote?.provider);\n\n if (!providerCode) {\n throw new Error('Missing provider code for fiat submission');\n }\n\n updateTransaction(\n {\n transactionId,\n messenger,\n note: 'Persist fiat order metadata',\n },\n (tx) => {\n tx.metamaskPay ??= {};\n tx.metamaskPay.fiat = { orderId, provider: providerCode };\n },\n );\n\n log('Starting fiat order polling', {\n orderId,\n providerCode,\n transactionId,\n });\n\n const fiatQuote = request.quotes[0];\n\n if (!fiatQuote) {\n throw new Error('Missing fiat quote for relay submission');\n }\n\n const fiatOptions = getFiatOptions(messenger);\n\n const order = fiatOptions?.testFundingSource\n ? await fundFiatOrderFromTestSource({\n fiat: fiatOptions,\n messenger,\n quote: fiatQuote,\n transaction,\n })\n : await waitForOrderCompletion({\n messenger,\n orderCode: orderId,\n providerCode,\n transactionId,\n walletAddress,\n });\n\n log('Fiat order completed', {\n cryptoAmount: order.cryptoAmount,\n orderId,\n transactionId,\n });\n\n return await submitRelayAfterFiatCompletion({ order, request });\n}\n\nfunction getFiatOptions(\n messenger: TransactionPayControllerMessenger,\n): TransactionPayFiatOptions | undefined {\n try {\n return messenger.call('TransactionPayController:getFiatOptions');\n } catch (error) {\n log('Failed to retrieve fiat options', error);\n return undefined;\n }\n}\n\n/**\n * Validates that the 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 */\nfunction 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 `Fiat order asset mismatch for transaction ${transactionId}: ` +\n `expected ${expectedAssetId}, got ${orderAssetId}`,\n );\n }\n\n if (orderChainId && orderChainId !== expectedChainId) {\n throw new Error(\n `Fiat order chain mismatch for transaction ${transactionId}: ` +\n `expected ${expectedChainId}, got ${orderChainId}`,\n );\n }\n}\n\n/**\n * Polls the on-ramp order until it reaches a terminal status.\n *\n * @param options - The polling options.\n * @param options.messenger - Controller messenger for calling `RampsController:getOrder`.\n * @param options.orderCode - The order identifier within the provider.\n * @param options.providerCode - The on-ramp provider code (e.g. \"transak\").\n * @param options.transactionId - Transaction ID for logging.\n * @param options.walletAddress - Wallet address associated with the order.\n * @returns The completed order data.\n */\nasync function waitForOrderCompletion({\n messenger,\n orderCode,\n providerCode,\n transactionId,\n walletAddress,\n}: {\n messenger: TransactionPayControllerMessenger;\n orderCode: string;\n providerCode: string;\n transactionId: string;\n walletAddress: string;\n}): Promise<RampsOrder> {\n const pollIntervalMs = getFiatOrderPollIntervalMs(messenger);\n const pollTimeoutMs = getFiatOrderPollTimeoutMs(messenger);\n const startTime = Date.now();\n let lastStatus: string | undefined;\n\n while (true) {\n let order: RampsOrder | undefined;\n\n try {\n order = await messenger.call(\n 'RampsController:getOrder',\n providerCode,\n orderCode,\n walletAddress,\n );\n } catch (error) {\n log('Order polling network error', error);\n }\n\n if (order) {\n lastStatus = order.status;\n\n log('Polled fiat order', {\n orderStatus: order.status,\n providerCode,\n transactionId,\n });\n\n if (order.status === RampsOrderStatus.Completed) {\n return order;\n }\n\n if (TERMINAL_FAILURE_STATUSES.includes(order.status)) {\n throw new Error(`Fiat order ${order.status.toLowerCase()}`);\n }\n }\n\n if (Date.now() - startTime >= pollTimeoutMs) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));\n }\n}\n\n/**\n * Re-quotes and submits the relay leg using the settled amount from a completed fiat order.\n *\n * @param options - The submission options.\n * @param options.order - The completed on-ramp order containing the settled crypto amount.\n * @param options.request - The original fiat strategy execute request.\n * @returns An object containing the relay transaction hash if available.\n */\nasync function submitRelayAfterFiatCompletion({\n order,\n request,\n}: {\n order: RampsOrder;\n request: PayStrategyExecuteRequest<FiatQuote>;\n}): Promise<{ transactionHash?: Hex }> {\n const { messenger, quotes, transaction } = request;\n const transactionId = transaction.id;\n\n if (quotes.length > 1) {\n throw new Error('Multiple fiat quotes are not supported for submission');\n }\n\n const fiatQuote = quotes[0];\n const isDirectMusd = isDirectMusdMoneyAccountQuote(fiatQuote);\n\n if (isDirectMusd) {\n validateOrderAsset({\n expectedAsset: MUSD_MONAD_FIAT_ASSET,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset: MUSD_MONAD_FIAT_ASSET,\n walletAddress: transaction.txParams.from as Hex,\n });\n\n return await submitDirectMusdVaultDeposit({\n request,\n sourceAmountRaw,\n transaction,\n });\n }\n\n const fiatAsset = deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const baseRequest = fiatQuote.request;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress: baseRequest.from,\n });\n\n if (!fiatQuote.original.relayQuote) {\n throw new Error('Missing Relay quote for fiat submission');\n }\n\n const hasNestedCalldata = (transaction.nestedTransactions?.length ?? 0) >= 2;\n\n // Transactions with nested calldata (e.g. moneyAccountDeposit with\n // approve + deposit) need a three-phase flow: discovery quote to learn\n // the target amount, calldata re-encoding, then a delegation quote.\n // Simple deposits (Perps, Predict) skip straight to a single EXACT_INPUT\n // relay quote — cheaper fees, no leftover dust, one fewer request.\n if (hasNestedCalldata) {\n return await submitWithTransactionData({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n }\n\n return await submitSimpleRelay({\n baseRequest,\n request,\n sourceAmountRaw,\n transaction,\n });\n}\n\nfunction getWalletAddress({\n quotes,\n transaction,\n accountOverride,\n}: {\n quotes: PayStrategyExecuteRequest<FiatQuote>['quotes'];\n transaction: PayStrategyExecuteRequest<FiatQuote>['transaction'];\n accountOverride: Hex | undefined;\n}): Hex {\n const address = isDirectMusdMoneyAccountQuote(quotes[0])\n ? transaction.txParams.from\n : (accountOverride ?? transaction.txParams.from);\n\n if (!address) {\n throw new Error('Missing wallet address for fiat submission');\n }\n\n return address as Hex;\n}\n"]}
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fundFiatOrderFromTestSource = void 0;
4
+ const abi_1 = require("@ethersproject/abi");
5
+ const controller_utils_1 = require("@metamask/controller-utils");
6
+ const ramps_controller_1 = require("@metamask/ramps-controller");
7
+ const transaction_controller_1 = require("@metamask/transaction-controller");
8
+ const utils_1 = require("@metamask/utils");
9
+ const bignumber_js_1 = require("bignumber.js");
10
+ const constants_1 = require("../../constants.cjs");
11
+ const logger_1 = require("../../logger.cjs");
12
+ const provider_1 = require("../../utils/provider.cjs");
13
+ const token_1 = require("../../utils/token.cjs");
14
+ const transaction_1 = require("../../utils/transaction.cjs");
15
+ const fiat_direct_musd_1 = require("./fiat-direct-musd.cjs");
16
+ const utils_2 = require("./utils.cjs");
17
+ const utils_3 = require("./utils.cjs");
18
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'fiat-test-funding');
19
+ const TOKEN_TRANSFER_INTERFACE = new abi_1.Interface([
20
+ 'function transfer(address to, uint256 amount)',
21
+ ]);
22
+ /**
23
+ * Funds the fiat recipient from a test source instead of waiting for ramps.
24
+ *
25
+ * @param options - Test funding options.
26
+ * @param options.fiat - Fiat local-QA execution options.
27
+ * @param options.messenger - Controller messenger.
28
+ * @param options.quote - Fiat quote being submitted.
29
+ * @param options.transaction - Original transaction metadata.
30
+ * @returns A synthetic completed ramps order for the existing fiat submit flow.
31
+ */
32
+ async function fundFiatOrderFromTestSource({ fiat, messenger, quote, transaction, }) {
33
+ const fundingSource = fiat.testFundingSource;
34
+ if (!fundingSource) {
35
+ throw new Error('Missing fiat test funding source');
36
+ }
37
+ const isDirectMusd = (0, fiat_direct_musd_1.isDirectMusdMoneyAccountQuote)(quote);
38
+ const fiatAsset = isDirectMusd
39
+ ? {
40
+ address: quote.request.sourceTokenAddress,
41
+ chainId: quote.request.sourceChainId,
42
+ }
43
+ : (0, utils_2.deriveFiatAssetForFiatPayment)(transaction, messenger);
44
+ const recipient = getFiatFundingRecipient({ quote, transaction });
45
+ const cryptoAmount = fiat.testAmountOverride ?? quote.original.rampsQuote.quote.amountOut;
46
+ const tokenInfo = (0, token_1.getTokenInfo)(messenger, fiatAsset.address, fiatAsset.chainId);
47
+ if (!tokenInfo) {
48
+ throw new Error(`Unable to resolve fiat test funding token info for ${fiatAsset.address} on chain ${fiatAsset.chainId}`);
49
+ }
50
+ const amountRaw = (0, utils_3.getRawSourceAmountFromOrderCryptoAmount)({
51
+ cryptoAmount,
52
+ decimals: tokenInfo.decimals,
53
+ });
54
+ log('Preparing fiat test funding transfer', {
55
+ amountRaw,
56
+ chainId: fiatAsset.chainId,
57
+ fundingSource,
58
+ recipient,
59
+ testAmountOverride: fiat.testAmountOverride,
60
+ });
61
+ await assertTestFundingBalances({
62
+ amountRaw,
63
+ fiatAsset,
64
+ fundingSource,
65
+ messenger,
66
+ symbol: tokenInfo.symbol,
67
+ });
68
+ const txHash = await submitTestFundingTransfer({
69
+ amountRaw,
70
+ fiatAsset,
71
+ fundingSource,
72
+ messenger,
73
+ recipient,
74
+ });
75
+ log('Fiat test funding complete', {
76
+ amountRaw,
77
+ chainId: fiatAsset.chainId,
78
+ fundingSource,
79
+ recipient,
80
+ txHash,
81
+ });
82
+ return {
83
+ cryptoAmount,
84
+ cryptoCurrency: {
85
+ assetId: (0, token_1.buildCaipAssetType)(fiatAsset.chainId, fiatAsset.address),
86
+ chainId: `eip155:${Number(fiatAsset.chainId)}`,
87
+ symbol: tokenInfo.symbol,
88
+ },
89
+ status: ramps_controller_1.RampsOrderStatus.Completed,
90
+ txHash,
91
+ };
92
+ }
93
+ exports.fundFiatOrderFromTestSource = fundFiatOrderFromTestSource;
94
+ function getFiatFundingRecipient({ quote, transaction, }) {
95
+ if ((0, fiat_direct_musd_1.isDirectMusdMoneyAccountQuote)(quote)) {
96
+ const moneyAccountAddress = transaction.txParams.from;
97
+ if (!moneyAccountAddress) {
98
+ throw new Error('Missing Money Account address for fiat test funding');
99
+ }
100
+ return moneyAccountAddress;
101
+ }
102
+ return quote.request.from;
103
+ }
104
+ async function assertTestFundingBalances({ amountRaw, fiatAsset, fundingSource, messenger, symbol, }) {
105
+ const balance = await (0, token_1.getLiveTokenBalance)(messenger, fundingSource, fiatAsset.chainId, fiatAsset.address);
106
+ if (new bignumber_js_1.BigNumber(balance).lt(amountRaw)) {
107
+ throw new Error(`Fiat test funding source has insufficient ${symbol} on chain ${fiatAsset.chainId}. ` +
108
+ `Required: ${amountRaw}, Available: ${balance}, Source: ${fundingSource}`);
109
+ }
110
+ const nativeToken = (0, token_1.getNativeToken)(fiatAsset.chainId);
111
+ const isNative = isNativeFiatAsset(fiatAsset);
112
+ const nativeBalance = isNative
113
+ ? balance
114
+ : await (0, token_1.getLiveTokenBalance)(messenger, fundingSource, fiatAsset.chainId, nativeToken);
115
+ const requiredNativeBalance = isNative ? amountRaw : '0';
116
+ if (new bignumber_js_1.BigNumber(nativeBalance).lte(requiredNativeBalance)) {
117
+ throw new Error(`Fiat test funding source has insufficient native gas on chain ${fiatAsset.chainId}. ` +
118
+ `Native balance: ${nativeBalance}, Source: ${fundingSource}`);
119
+ }
120
+ }
121
+ async function submitTestFundingTransfer({ amountRaw, fiatAsset, fundingSource, messenger, recipient, }) {
122
+ const networkClientId = (0, provider_1.getNetworkClientId)(messenger, fiatAsset.chainId);
123
+ const params = buildTestFundingTransferParams({
124
+ amountRaw,
125
+ fiatAsset,
126
+ fundingSource,
127
+ recipient,
128
+ });
129
+ const result = await messenger.call('TransactionController:addTransaction', params, {
130
+ isInternal: true,
131
+ networkClientId,
132
+ origin: controller_utils_1.ORIGIN_METAMASK,
133
+ requireApproval: false,
134
+ type: transaction_controller_1.TransactionType.simpleSend,
135
+ });
136
+ const txHash = (await result.result);
137
+ await (0, transaction_1.waitForTransactionConfirmed)(result.transactionMeta.id, messenger);
138
+ return txHash;
139
+ }
140
+ function buildTestFundingTransferParams({ amountRaw, fiatAsset, fundingSource, recipient, }) {
141
+ if (isNativeFiatAsset(fiatAsset)) {
142
+ return {
143
+ from: fundingSource,
144
+ to: recipient,
145
+ value: (0, controller_utils_1.toHex)(amountRaw),
146
+ };
147
+ }
148
+ return {
149
+ data: buildTokenTransferData(recipient, amountRaw),
150
+ from: fundingSource,
151
+ to: fiatAsset.address,
152
+ value: '0x0',
153
+ };
154
+ }
155
+ function buildTokenTransferData(recipient, amountRaw) {
156
+ return TOKEN_TRANSFER_INTERFACE.encodeFunctionData('transfer', [
157
+ recipient,
158
+ amountRaw,
159
+ ]);
160
+ }
161
+ function isNativeFiatAsset({ address, chainId, }) {
162
+ const normalizedAddress = address.toLowerCase();
163
+ return (normalizedAddress === constants_1.NATIVE_TOKEN_ADDRESS.toLowerCase() ||
164
+ normalizedAddress === (0, token_1.getNativeToken)(chainId).toLowerCase());
165
+ }
166
+ //# sourceMappingURL=fiat-test-funding.cjs.map