@metamask-previews/transaction-pay-controller 23.1.0-preview-a65eb72 → 23.1.0-preview-e37aff3
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 +0 -5
- package/dist/TransactionPayController-method-action-types.cjs.map +1 -1
- package/dist/TransactionPayController-method-action-types.d.cts +1 -5
- package/dist/TransactionPayController-method-action-types.d.cts.map +1 -1
- package/dist/TransactionPayController-method-action-types.d.mts +1 -5
- package/dist/TransactionPayController-method-action-types.d.mts.map +1 -1
- package/dist/TransactionPayController-method-action-types.mjs.map +1 -1
- package/dist/TransactionPayController.cjs +3 -9
- package/dist/TransactionPayController.cjs.map +1 -1
- package/dist/TransactionPayController.d.cts +2 -3
- package/dist/TransactionPayController.d.cts.map +1 -1
- package/dist/TransactionPayController.d.mts +2 -3
- package/dist/TransactionPayController.d.mts.map +1 -1
- package/dist/TransactionPayController.mjs +3 -9
- package/dist/TransactionPayController.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/strategy/fiat/fiat-submit.cjs +101 -27
- package/dist/strategy/fiat/fiat-submit.cjs.map +1 -1
- package/dist/strategy/fiat/fiat-submit.d.cts.map +1 -1
- package/dist/strategy/fiat/fiat-submit.d.mts.map +1 -1
- package/dist/strategy/fiat/fiat-submit.mjs +101 -27
- package/dist/strategy/fiat/fiat-submit.mjs.map +1 -1
- package/dist/strategy/fiat/utils.cjs +1 -66
- package/dist/strategy/fiat/utils.cjs.map +1 -1
- package/dist/strategy/fiat/utils.d.cts +0 -32
- package/dist/strategy/fiat/utils.d.cts.map +1 -1
- package/dist/strategy/fiat/utils.d.mts +0 -32
- package/dist/strategy/fiat/utils.d.mts.map +1 -1
- package/dist/strategy/fiat/utils.mjs +0 -63
- package/dist/strategy/fiat/utils.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +0 -22
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +0 -22
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils/feature-flags.cjs +1 -41
- package/dist/utils/feature-flags.cjs.map +1 -1
- package/dist/utils/feature-flags.d.cts +0 -22
- package/dist/utils/feature-flags.d.cts.map +1 -1
- package/dist/utils/feature-flags.d.mts +0 -22
- package/dist/utils/feature-flags.d.mts.map +1 -1
- package/dist/utils/feature-flags.mjs +0 -38
- package/dist/utils/feature-flags.mjs.map +1 -1
- package/dist/utils/quotes.cjs +2 -3
- package/dist/utils/quotes.cjs.map +1 -1
- package/dist/utils/quotes.d.cts.map +1 -1
- package/dist/utils/quotes.d.mts.map +1 -1
- package/dist/utils/quotes.mjs +2 -3
- package/dist/utils/quotes.mjs.map +1 -1
- package/dist/utils/totals.cjs +7 -41
- package/dist/utils/totals.cjs.map +1 -1
- package/dist/utils/totals.d.cts +1 -3
- package/dist/utils/totals.d.cts.map +1 -1
- package/dist/utils/totals.d.mts +1 -3
- package/dist/utils/totals.d.mts.map +1 -1
- package/dist/utils/totals.mjs +7 -41
- package/dist/utils/totals.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/strategy/fiat/fiat-submit-simple.cjs +0 -61
- package/dist/strategy/fiat/fiat-submit-simple.cjs.map +0 -1
- package/dist/strategy/fiat/fiat-submit-simple.d.cts +0 -23
- package/dist/strategy/fiat/fiat-submit-simple.d.cts.map +0 -1
- package/dist/strategy/fiat/fiat-submit-simple.d.mts +0 -23
- package/dist/strategy/fiat/fiat-submit-simple.d.mts.map +0 -1
- package/dist/strategy/fiat/fiat-submit-simple.mjs +0 -57
- package/dist/strategy/fiat/fiat-submit-simple.mjs.map +0 -1
- package/dist/strategy/fiat/fiat-submit-with-calldata.cjs +0 -185
- package/dist/strategy/fiat/fiat-submit-with-calldata.cjs.map +0 -1
- package/dist/strategy/fiat/fiat-submit-with-calldata.d.cts +0 -27
- package/dist/strategy/fiat/fiat-submit-with-calldata.d.cts.map +0 -1
- package/dist/strategy/fiat/fiat-submit-with-calldata.d.mts +0 -27
- package/dist/strategy/fiat/fiat-submit-with-calldata.d.mts.map +0 -1
- package/dist/strategy/fiat/fiat-submit-with-calldata.mjs +0 -181
- package/dist/strategy/fiat/fiat-submit-with-calldata.mjs.map +0 -1
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,6BAA6B,EAC7B,8BAA8B,EAC9B,iBAAiB,EACjB,yBAAyB,EACzB,eAAe,EACf,sBAAsB,EACtB,8BAA8B,EAC9B,+BAA+B,EAC/B,8BAA8B,EAC9B,sCAAsC,EACtC,iCAAiC,EACjC,+BAA+B,EAC/B,6BAA6B,EAC7B,mBAAmB,EACnB,wCAAwC,EACxC,uBAAuB,EACvB,mBAAmB,EACnB,2BAA2B,EAC3B,0BAA0B,EAC1B,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,GAC1B,oBAAgB;AACjB,YAAY,EACV,sDAAsD,EACtD,yCAAyC,EACzC,+DAA+D,EAC/D,gEAAgE,EAChE,kDAAkD,EAClD,gDAAgD,EAChD,+CAA+C,GAChD,2DAAuD;AACxD,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,wBAAoB;AACtE,OAAO,EAAE,wBAAwB,EAAE,uCAAmC;AACtE,OAAO,EAAE,yBAAyB,EAAE,gDAA4C;AAChF,YAAY,EAAE,yBAAyB,EAAE,oCAAgC"}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,wBAAoB;AACtE,OAAO,EAAE,wBAAwB,EAAE,uCAAmC;AACtE,OAAO,EAAE,yBAAyB,EAAE,gDAA4C","sourcesContent":["export type {\n GetPaymentOverrideDataRequest,\n GetPaymentOverrideDataResponse,\n TransactionConfig,\n TransactionConfigCallback,\n TransactionData,\n TransactionFiatPayment,\n TransactionFiatPaymentCallback,\n TransactionPayControllerActions,\n TransactionPayControllerEvents,\n TransactionPayControllerGetStateAction,\n TransactionPayControllerMessenger,\n TransactionPayControllerOptions,\n TransactionPayControllerState,\n PolymarketCallbacks,\n TransactionPayControllerStateChangeEvent,\n TransactionPaymentToken,\n TransactionPayQuote,\n TransactionPayRequiredToken,\n TransactionPaySourceAmount,\n TransactionPayTotals,\n UpdateFiatPaymentRequest,\n UpdatePaymentTokenRequest,\n} from './types';\nexport type {\n TransactionPayControllerGetDelegationTransactionAction,\n TransactionPayControllerGetStrategyAction,\n TransactionPayControllerPolymarketGetDepositWalletAddressAction,\n TransactionPayControllerPolymarketSubmitDepositWalletBatchAction,\n TransactionPayControllerSetTransactionConfigAction,\n TransactionPayControllerUpdatePaymentTokenAction,\n TransactionPayControllerUpdateFiatPaymentAction,\n} from './TransactionPayController-method-action-types';\nexport { PaymentOverride, TransactionPayStrategy } from './constants';\nexport { TransactionPayController } from './TransactionPayController';\nexport { TransactionPayPublishHook } from './helpers/TransactionPayPublishHook';\nexport type { TransactionPayBridgeQuote } from './strategy/bridge/types';\n"]}
|
|
@@ -3,15 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.submitFiatQuotes = void 0;
|
|
4
4
|
const ramps_controller_1 = require("@metamask/ramps-controller");
|
|
5
5
|
const utils_1 = require("@metamask/utils");
|
|
6
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
6
7
|
const logger_1 = require("../../logger.cjs");
|
|
7
8
|
const token_1 = require("../../utils/token.cjs");
|
|
8
9
|
const transaction_1 = require("../../utils/transaction.cjs");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
10
|
+
const relay_quotes_1 = require("../relay/relay-quotes.cjs");
|
|
11
|
+
const relay_submit_1 = require("../relay/relay-submit.cjs");
|
|
11
12
|
const utils_2 = require("./utils.cjs");
|
|
12
13
|
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'fiat-submit');
|
|
13
14
|
const ORDER_POLL_INTERVAL_MS = 1000;
|
|
14
15
|
const ORDER_POLL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
16
|
+
const MAX_SLIPPAGE_PERCENT = 5;
|
|
15
17
|
const TERMINAL_FAILURE_STATUSES = [
|
|
16
18
|
ramps_controller_1.RampsOrderStatus.Cancelled,
|
|
17
19
|
ramps_controller_1.RampsOrderStatus.Failed,
|
|
@@ -31,19 +33,17 @@ const TERMINAL_FAILURE_STATUSES = [
|
|
|
31
33
|
async function submitFiatQuotes(request) {
|
|
32
34
|
const { messenger, transaction } = request;
|
|
33
35
|
const transactionId = transaction.id;
|
|
34
|
-
const
|
|
35
|
-
const transactionData = state.transactionData[transactionId];
|
|
36
|
-
const walletAddress = (transactionData?.accountOverride ??
|
|
37
|
-
transaction.txParams.from);
|
|
36
|
+
const walletAddress = transaction.txParams.from;
|
|
38
37
|
if (!walletAddress) {
|
|
39
38
|
throw new Error('Missing wallet address for fiat submission');
|
|
40
39
|
}
|
|
41
|
-
const
|
|
40
|
+
const state = messenger.call('TransactionPayController:getState');
|
|
41
|
+
const fiatPayment = state.transactionData[transactionId]?.fiatPayment;
|
|
42
42
|
const orderId = fiatPayment?.orderId;
|
|
43
43
|
if (!orderId) {
|
|
44
44
|
throw new Error('Missing order ID for fiat submission');
|
|
45
45
|
}
|
|
46
|
-
const providerCode =
|
|
46
|
+
const providerCode = extractProviderCode(fiatPayment?.rampsQuote?.provider);
|
|
47
47
|
if (!providerCode) {
|
|
48
48
|
throw new Error('Missing provider code for fiat submission');
|
|
49
49
|
}
|
|
@@ -75,6 +75,25 @@ async function submitFiatQuotes(request) {
|
|
|
75
75
|
return await submitRelayAfterFiatCompletion({ order, request });
|
|
76
76
|
}
|
|
77
77
|
exports.submitFiatQuotes = submitFiatQuotes;
|
|
78
|
+
/**
|
|
79
|
+
* Extracts the provider code from a ramps provider string.
|
|
80
|
+
*
|
|
81
|
+
* Accepts the canonical provider code (e.g. `transak-native`) and, for
|
|
82
|
+
* backwards compatibility, the legacy path form (e.g. `/providers/transak-native`).
|
|
83
|
+
*
|
|
84
|
+
* @param provider - Canonical provider code, or legacy provider path.
|
|
85
|
+
* @returns The provider code, or `null` if the format is invalid.
|
|
86
|
+
*/
|
|
87
|
+
function extractProviderCode(provider) {
|
|
88
|
+
if (!provider) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const parts = provider.split('/').filter(Boolean);
|
|
92
|
+
if (parts[0] === 'providers') {
|
|
93
|
+
return parts[1] ?? null;
|
|
94
|
+
}
|
|
95
|
+
return parts.length === 1 ? parts[0] : null;
|
|
96
|
+
}
|
|
78
97
|
/**
|
|
79
98
|
* Validates that the completed order's crypto asset matches the expected fiat asset.
|
|
80
99
|
*
|
|
@@ -97,6 +116,36 @@ function validateOrderAsset({ expectedAsset, orderCrypto, transactionId, }) {
|
|
|
97
116
|
`expected ${expectedChainId}, got ${orderChainId}`);
|
|
98
117
|
}
|
|
99
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Validates that the re-quoted relay target output hasn't drifted beyond the
|
|
121
|
+
* acceptable slippage threshold compared to the original quote shown to the user.
|
|
122
|
+
*
|
|
123
|
+
* @param options - The validation options.
|
|
124
|
+
* @param options.originalTargetRaw - Raw target amount from the original relay quote.
|
|
125
|
+
* @param options.reQuotedTargetRaw - Raw target amount from the re-quoted relay.
|
|
126
|
+
* @param options.transactionId - Transaction ID for error reporting.
|
|
127
|
+
*/
|
|
128
|
+
function validateRelaySlippage({ originalTargetRaw, reQuotedTargetRaw, transactionId, }) {
|
|
129
|
+
const original = new bignumber_js_1.BigNumber(originalTargetRaw);
|
|
130
|
+
const reQuoted = new bignumber_js_1.BigNumber(reQuotedTargetRaw);
|
|
131
|
+
if (!original.gt(0) || !reQuoted.gt(0)) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const slippagePercent = original
|
|
135
|
+
.minus(reQuoted)
|
|
136
|
+
.dividedBy(original)
|
|
137
|
+
.multipliedBy(100);
|
|
138
|
+
log('Relay slippage check', {
|
|
139
|
+
originalTargetRaw,
|
|
140
|
+
reQuotedTargetRaw,
|
|
141
|
+
slippagePercent: slippagePercent.toFixed(2),
|
|
142
|
+
transactionId,
|
|
143
|
+
});
|
|
144
|
+
if (slippagePercent.gt(MAX_SLIPPAGE_PERCENT)) {
|
|
145
|
+
throw new Error(`Relay re-quote slippage too high for transaction ` +
|
|
146
|
+
`${slippagePercent.toFixed(2)}% exceeds ${MAX_SLIPPAGE_PERCENT}% max`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
100
149
|
/**
|
|
101
150
|
* Polls the on-ramp order until it reaches a terminal status.
|
|
102
151
|
*
|
|
@@ -162,33 +211,58 @@ async function submitRelayAfterFiatCompletion({ order, request, }) {
|
|
|
162
211
|
orderCrypto: order.cryptoCurrency,
|
|
163
212
|
transactionId,
|
|
164
213
|
});
|
|
165
|
-
const
|
|
166
|
-
const walletAddress = baseRequest.from;
|
|
214
|
+
const walletAddress = transaction.txParams.from;
|
|
167
215
|
const sourceAmountRaw = await (0, utils_2.resolveSourceAmountRaw)({
|
|
168
216
|
messenger,
|
|
169
217
|
order,
|
|
170
218
|
fiatAsset,
|
|
171
219
|
walletAddress,
|
|
172
220
|
});
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
transaction,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
return await (0, fiat_submit_simple_1.submitSimpleRelay)({
|
|
188
|
-
baseRequest,
|
|
189
|
-
request,
|
|
221
|
+
const baseRequest = quotes[0].request;
|
|
222
|
+
const relayRequest = {
|
|
223
|
+
...baseRequest,
|
|
224
|
+
isMaxAmount: true,
|
|
225
|
+
isPostQuote: false,
|
|
226
|
+
sourceBalanceRaw: sourceAmountRaw,
|
|
227
|
+
sourceTokenAmount: sourceAmountRaw,
|
|
228
|
+
};
|
|
229
|
+
log('Re-quoting relay from completed fiat order', {
|
|
230
|
+
completedOrderAmount: order.cryptoAmount,
|
|
231
|
+
relayRequest,
|
|
190
232
|
sourceAmountRaw,
|
|
233
|
+
transactionId,
|
|
234
|
+
});
|
|
235
|
+
const relayQuotes = await (0, relay_quotes_1.getRelayQuotes)({
|
|
236
|
+
accountSupports7702: request.accountSupports7702,
|
|
237
|
+
messenger,
|
|
238
|
+
requests: [relayRequest],
|
|
191
239
|
transaction,
|
|
192
240
|
});
|
|
241
|
+
if (!relayQuotes.length) {
|
|
242
|
+
throw new Error('No relay quotes returned for completed fiat order');
|
|
243
|
+
}
|
|
244
|
+
const originalRelayQuote = quotes[0].original.relayQuote;
|
|
245
|
+
validateRelaySlippage({
|
|
246
|
+
originalTargetRaw: originalRelayQuote.details.currencyOut.amount,
|
|
247
|
+
reQuotedTargetRaw: relayQuotes[0].original.details.currencyOut.amount,
|
|
248
|
+
transactionId,
|
|
249
|
+
});
|
|
250
|
+
log('Received relay quotes for completed fiat order', {
|
|
251
|
+
relayQuoteCount: relayQuotes.length,
|
|
252
|
+
transactionId,
|
|
253
|
+
});
|
|
254
|
+
const relaySubmitRequest = {
|
|
255
|
+
accountSupports7702: request.accountSupports7702,
|
|
256
|
+
isSmartTransaction: request.isSmartTransaction,
|
|
257
|
+
messenger,
|
|
258
|
+
quotes: relayQuotes,
|
|
259
|
+
transaction,
|
|
260
|
+
};
|
|
261
|
+
const relayResult = await (0, relay_submit_1.submitRelayQuotes)(relaySubmitRequest);
|
|
262
|
+
log('Relay submission completed after fiat order', {
|
|
263
|
+
relayResult,
|
|
264
|
+
transactionId,
|
|
265
|
+
});
|
|
266
|
+
return relayResult;
|
|
193
267
|
}
|
|
194
268
|
//# sourceMappingURL=fiat-submit.cjs.map
|
|
@@ -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 { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport type { TransactionPayFiatAsset } from './constants';\nimport { submitSimpleRelay } from './fiat-submit-simple';\nimport { submitWithCalldataReEncoding } from './fiat-submit-with-calldata';\nimport type { FiatQuote } from './types';\nimport {\n deriveFiatAssetForFiatPayment,\n extractProviderCode,\n resolveSourceAmountRaw,\n} from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst ORDER_POLL_INTERVAL_MS = 1000;\nconst ORDER_POLL_TIMEOUT_MS = 10 * 60 * 1000;\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 const walletAddress = (transactionData?.accountOverride ??\n transaction.txParams.from) as Hex | undefined;\n\n if (!walletAddress) {\n throw new Error('Missing wallet address for fiat submission');\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 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 >= ORDER_POLL_TIMEOUT_MS) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, ORDER_POLL_INTERVAL_MS));\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 fiatAsset = deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const baseRequest = quotes[0].request;\n const walletAddress = baseRequest.from;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress,\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 submitWithCalldataReEncoding({\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"]}
|
|
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';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n} from '../../types';\nimport { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport { getRelayQuotes } from '../relay/relay-quotes';\nimport { submitRelayQuotes } from '../relay/relay-submit';\nimport type { RelayQuote } from '../relay/types';\nimport type { TransactionPayFiatAsset } from './constants';\nimport type { FiatQuote } from './types';\nimport { deriveFiatAssetForFiatPayment, resolveSourceAmountRaw } from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst ORDER_POLL_INTERVAL_MS = 1000;\nconst ORDER_POLL_TIMEOUT_MS = 10 * 60 * 1000;\nconst MAX_SLIPPAGE_PERCENT = 5;\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 walletAddress = transaction.txParams.from as Hex | undefined;\n\n if (!walletAddress) {\n throw new Error('Missing wallet address for fiat submission');\n }\n\n const state = messenger.call('TransactionPayController:getState');\n const fiatPayment = state.transactionData[transactionId]?.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 * 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 */\nfunction extractProviderCode(provider: string | undefined): 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 * 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 * Validates that the re-quoted relay target output hasn't drifted beyond the\n * acceptable slippage threshold compared to the original quote shown to the user.\n *\n * @param options - The validation options.\n * @param options.originalTargetRaw - Raw target amount from the original relay quote.\n * @param options.reQuotedTargetRaw - Raw target amount from the re-quoted relay.\n * @param options.transactionId - Transaction ID for error reporting.\n */\nfunction validateRelaySlippage({\n originalTargetRaw,\n reQuotedTargetRaw,\n transactionId,\n}: {\n originalTargetRaw: string;\n reQuotedTargetRaw: string;\n transactionId: string;\n}): void {\n const original = new BigNumber(originalTargetRaw);\n const reQuoted = new BigNumber(reQuotedTargetRaw);\n\n if (!original.gt(0) || !reQuoted.gt(0)) {\n return;\n }\n\n const slippagePercent = original\n .minus(reQuoted)\n .dividedBy(original)\n .multipliedBy(100);\n\n log('Relay slippage check', {\n originalTargetRaw,\n reQuotedTargetRaw,\n slippagePercent: slippagePercent.toFixed(2),\n transactionId,\n });\n\n if (slippagePercent.gt(MAX_SLIPPAGE_PERCENT)) {\n throw new Error(\n `Relay re-quote slippage too high for transaction ` +\n `${slippagePercent.toFixed(2)}% exceeds ${MAX_SLIPPAGE_PERCENT}% max`,\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 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 >= ORDER_POLL_TIMEOUT_MS) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, ORDER_POLL_INTERVAL_MS));\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 fiatAsset = deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const walletAddress = transaction.txParams.from as Hex;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress,\n });\n\n const baseRequest = quotes[0].request;\n const relayRequest: QuoteRequest = {\n ...baseRequest,\n isMaxAmount: true,\n isPostQuote: false,\n sourceBalanceRaw: sourceAmountRaw,\n sourceTokenAmount: sourceAmountRaw,\n };\n\n log('Re-quoting relay from completed fiat order', {\n completedOrderAmount: order.cryptoAmount,\n relayRequest,\n sourceAmountRaw,\n transactionId,\n });\n\n const relayQuotes = await getRelayQuotes({\n accountSupports7702: request.accountSupports7702,\n messenger,\n requests: [relayRequest],\n transaction,\n });\n\n if (!relayQuotes.length) {\n throw new Error('No relay quotes returned for completed fiat order');\n }\n\n const originalRelayQuote = quotes[0].original.relayQuote;\n validateRelaySlippage({\n originalTargetRaw: originalRelayQuote.details.currencyOut.amount,\n reQuotedTargetRaw: relayQuotes[0].original.details.currencyOut.amount,\n transactionId,\n });\n\n log('Received relay quotes for completed fiat order', {\n relayQuoteCount: relayQuotes.length,\n transactionId,\n });\n\n const relaySubmitRequest: PayStrategyExecuteRequest<RelayQuote> = {\n accountSupports7702: request.accountSupports7702,\n isSmartTransaction: request.isSmartTransaction,\n messenger,\n quotes: relayQuotes,\n transaction,\n };\n\n const relayResult = await submitRelayQuotes(relaySubmitRequest);\n\n log('Relay submission completed after fiat order', {\n relayResult,\n transactionId,\n });\n\n return relayResult;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fiat-submit.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fiat-submit.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EAG1B,wBAAoB;AAOrB,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,CAwD/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fiat-submit.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fiat-submit.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EAG1B,wBAAoB;AAOrB,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,CAwD/C"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { RampsOrderStatus } from "@metamask/ramps-controller";
|
|
2
2
|
import { createModuleLogger } from "@metamask/utils";
|
|
3
|
+
import { BigNumber } from "bignumber.js";
|
|
3
4
|
import { projectLogger } from "../../logger.mjs";
|
|
4
5
|
import { buildCaipAssetType } from "../../utils/token.mjs";
|
|
5
6
|
import { updateTransaction } from "../../utils/transaction.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { deriveFiatAssetForFiatPayment,
|
|
7
|
+
import { getRelayQuotes } from "../relay/relay-quotes.mjs";
|
|
8
|
+
import { submitRelayQuotes } from "../relay/relay-submit.mjs";
|
|
9
|
+
import { deriveFiatAssetForFiatPayment, resolveSourceAmountRaw } from "./utils.mjs";
|
|
9
10
|
const log = createModuleLogger(projectLogger, 'fiat-submit');
|
|
10
11
|
const ORDER_POLL_INTERVAL_MS = 1000;
|
|
11
12
|
const ORDER_POLL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
13
|
+
const MAX_SLIPPAGE_PERCENT = 5;
|
|
12
14
|
const TERMINAL_FAILURE_STATUSES = [
|
|
13
15
|
RampsOrderStatus.Cancelled,
|
|
14
16
|
RampsOrderStatus.Failed,
|
|
@@ -28,14 +30,12 @@ const TERMINAL_FAILURE_STATUSES = [
|
|
|
28
30
|
export async function submitFiatQuotes(request) {
|
|
29
31
|
const { messenger, transaction } = request;
|
|
30
32
|
const transactionId = transaction.id;
|
|
31
|
-
const
|
|
32
|
-
const transactionData = state.transactionData[transactionId];
|
|
33
|
-
const walletAddress = (transactionData?.accountOverride ??
|
|
34
|
-
transaction.txParams.from);
|
|
33
|
+
const walletAddress = transaction.txParams.from;
|
|
35
34
|
if (!walletAddress) {
|
|
36
35
|
throw new Error('Missing wallet address for fiat submission');
|
|
37
36
|
}
|
|
38
|
-
const
|
|
37
|
+
const state = messenger.call('TransactionPayController:getState');
|
|
38
|
+
const fiatPayment = state.transactionData[transactionId]?.fiatPayment;
|
|
39
39
|
const orderId = fiatPayment?.orderId;
|
|
40
40
|
if (!orderId) {
|
|
41
41
|
throw new Error('Missing order ID for fiat submission');
|
|
@@ -71,6 +71,25 @@ export async function submitFiatQuotes(request) {
|
|
|
71
71
|
});
|
|
72
72
|
return await submitRelayAfterFiatCompletion({ order, request });
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Extracts the provider code from a ramps provider string.
|
|
76
|
+
*
|
|
77
|
+
* Accepts the canonical provider code (e.g. `transak-native`) and, for
|
|
78
|
+
* backwards compatibility, the legacy path form (e.g. `/providers/transak-native`).
|
|
79
|
+
*
|
|
80
|
+
* @param provider - Canonical provider code, or legacy provider path.
|
|
81
|
+
* @returns The provider code, or `null` if the format is invalid.
|
|
82
|
+
*/
|
|
83
|
+
function extractProviderCode(provider) {
|
|
84
|
+
if (!provider) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const parts = provider.split('/').filter(Boolean);
|
|
88
|
+
if (parts[0] === 'providers') {
|
|
89
|
+
return parts[1] ?? null;
|
|
90
|
+
}
|
|
91
|
+
return parts.length === 1 ? parts[0] : null;
|
|
92
|
+
}
|
|
74
93
|
/**
|
|
75
94
|
* Validates that the completed order's crypto asset matches the expected fiat asset.
|
|
76
95
|
*
|
|
@@ -93,6 +112,36 @@ function validateOrderAsset({ expectedAsset, orderCrypto, transactionId, }) {
|
|
|
93
112
|
`expected ${expectedChainId}, got ${orderChainId}`);
|
|
94
113
|
}
|
|
95
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Validates that the re-quoted relay target output hasn't drifted beyond the
|
|
117
|
+
* acceptable slippage threshold compared to the original quote shown to the user.
|
|
118
|
+
*
|
|
119
|
+
* @param options - The validation options.
|
|
120
|
+
* @param options.originalTargetRaw - Raw target amount from the original relay quote.
|
|
121
|
+
* @param options.reQuotedTargetRaw - Raw target amount from the re-quoted relay.
|
|
122
|
+
* @param options.transactionId - Transaction ID for error reporting.
|
|
123
|
+
*/
|
|
124
|
+
function validateRelaySlippage({ originalTargetRaw, reQuotedTargetRaw, transactionId, }) {
|
|
125
|
+
const original = new BigNumber(originalTargetRaw);
|
|
126
|
+
const reQuoted = new BigNumber(reQuotedTargetRaw);
|
|
127
|
+
if (!original.gt(0) || !reQuoted.gt(0)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const slippagePercent = original
|
|
131
|
+
.minus(reQuoted)
|
|
132
|
+
.dividedBy(original)
|
|
133
|
+
.multipliedBy(100);
|
|
134
|
+
log('Relay slippage check', {
|
|
135
|
+
originalTargetRaw,
|
|
136
|
+
reQuotedTargetRaw,
|
|
137
|
+
slippagePercent: slippagePercent.toFixed(2),
|
|
138
|
+
transactionId,
|
|
139
|
+
});
|
|
140
|
+
if (slippagePercent.gt(MAX_SLIPPAGE_PERCENT)) {
|
|
141
|
+
throw new Error(`Relay re-quote slippage too high for transaction ` +
|
|
142
|
+
`${slippagePercent.toFixed(2)}% exceeds ${MAX_SLIPPAGE_PERCENT}% max`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
96
145
|
/**
|
|
97
146
|
* Polls the on-ramp order until it reaches a terminal status.
|
|
98
147
|
*
|
|
@@ -158,33 +207,58 @@ async function submitRelayAfterFiatCompletion({ order, request, }) {
|
|
|
158
207
|
orderCrypto: order.cryptoCurrency,
|
|
159
208
|
transactionId,
|
|
160
209
|
});
|
|
161
|
-
const
|
|
162
|
-
const walletAddress = baseRequest.from;
|
|
210
|
+
const walletAddress = transaction.txParams.from;
|
|
163
211
|
const sourceAmountRaw = await resolveSourceAmountRaw({
|
|
164
212
|
messenger,
|
|
165
213
|
order,
|
|
166
214
|
fiatAsset,
|
|
167
215
|
walletAddress,
|
|
168
216
|
});
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
transaction,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
return await submitSimpleRelay({
|
|
184
|
-
baseRequest,
|
|
185
|
-
request,
|
|
217
|
+
const baseRequest = quotes[0].request;
|
|
218
|
+
const relayRequest = {
|
|
219
|
+
...baseRequest,
|
|
220
|
+
isMaxAmount: true,
|
|
221
|
+
isPostQuote: false,
|
|
222
|
+
sourceBalanceRaw: sourceAmountRaw,
|
|
223
|
+
sourceTokenAmount: sourceAmountRaw,
|
|
224
|
+
};
|
|
225
|
+
log('Re-quoting relay from completed fiat order', {
|
|
226
|
+
completedOrderAmount: order.cryptoAmount,
|
|
227
|
+
relayRequest,
|
|
186
228
|
sourceAmountRaw,
|
|
229
|
+
transactionId,
|
|
230
|
+
});
|
|
231
|
+
const relayQuotes = await getRelayQuotes({
|
|
232
|
+
accountSupports7702: request.accountSupports7702,
|
|
233
|
+
messenger,
|
|
234
|
+
requests: [relayRequest],
|
|
187
235
|
transaction,
|
|
188
236
|
});
|
|
237
|
+
if (!relayQuotes.length) {
|
|
238
|
+
throw new Error('No relay quotes returned for completed fiat order');
|
|
239
|
+
}
|
|
240
|
+
const originalRelayQuote = quotes[0].original.relayQuote;
|
|
241
|
+
validateRelaySlippage({
|
|
242
|
+
originalTargetRaw: originalRelayQuote.details.currencyOut.amount,
|
|
243
|
+
reQuotedTargetRaw: relayQuotes[0].original.details.currencyOut.amount,
|
|
244
|
+
transactionId,
|
|
245
|
+
});
|
|
246
|
+
log('Received relay quotes for completed fiat order', {
|
|
247
|
+
relayQuoteCount: relayQuotes.length,
|
|
248
|
+
transactionId,
|
|
249
|
+
});
|
|
250
|
+
const relaySubmitRequest = {
|
|
251
|
+
accountSupports7702: request.accountSupports7702,
|
|
252
|
+
isSmartTransaction: request.isSmartTransaction,
|
|
253
|
+
messenger,
|
|
254
|
+
quotes: relayQuotes,
|
|
255
|
+
transaction,
|
|
256
|
+
};
|
|
257
|
+
const relayResult = await submitRelayQuotes(relaySubmitRequest);
|
|
258
|
+
log('Relay submission completed after fiat order', {
|
|
259
|
+
relayResult,
|
|
260
|
+
transactionId,
|
|
261
|
+
});
|
|
262
|
+
return relayResult;
|
|
189
263
|
}
|
|
190
264
|
//# sourceMappingURL=fiat-submit.mjs.map
|
|
@@ -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 { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport type { TransactionPayFiatAsset } from './constants';\nimport { submitSimpleRelay } from './fiat-submit-simple';\nimport { submitWithCalldataReEncoding } from './fiat-submit-with-calldata';\nimport type { FiatQuote } from './types';\nimport {\n deriveFiatAssetForFiatPayment,\n extractProviderCode,\n resolveSourceAmountRaw,\n} from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst ORDER_POLL_INTERVAL_MS = 1000;\nconst ORDER_POLL_TIMEOUT_MS = 10 * 60 * 1000;\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 const walletAddress = (transactionData?.accountOverride ??\n transaction.txParams.from) as Hex | undefined;\n\n if (!walletAddress) {\n throw new Error('Missing wallet address for fiat submission');\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 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 >= ORDER_POLL_TIMEOUT_MS) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, ORDER_POLL_INTERVAL_MS));\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 fiatAsset = deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const baseRequest = quotes[0].request;\n const walletAddress = baseRequest.from;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress,\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 submitWithCalldataReEncoding({\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"]}
|
|
1
|
+
{"version":3,"file":"fiat-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,mCAAmC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,wBAAwB;AACrD,OAAO,EAAE,SAAS,EAAE,qBAAqB;AAEzC,OAAO,EAAE,aAAa,EAAE,yBAAqB;AAO7C,OAAO,EAAE,kBAAkB,EAAE,8BAA0B;AACvD,OAAO,EAAE,iBAAiB,EAAE,oCAAgC;AAC5D,OAAO,EAAE,cAAc,EAAE,kCAA8B;AACvD,OAAO,EAAE,iBAAiB,EAAE,kCAA8B;AAI1D,OAAO,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,oBAAgB;AAEhF,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAE7D,MAAM,sBAAsB,GAAG,IAAI,CAAC;AACpC,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC7C,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,MAAM,yBAAyB,GAAuB;IACpD,gBAAgB,CAAC,SAAS;IAC1B,gBAAgB,CAAC,MAAM;IACvB,gBAAgB,CAAC,SAAS;CAC3B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAA6C;IAE7C,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAC3C,MAAM,aAAa,GAAG,WAAW,CAAC,EAAE,CAAC;IACrC,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAuB,CAAC;IAEnE,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAClE,MAAM,WAAW,GAAG,KAAK,CAAC,eAAe,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC;IACtE,MAAM,OAAO,GAAG,WAAW,EAAE,OAAO,CAAC;IAErC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,YAAY,GAAG,mBAAmB,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAE5E,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,iBAAiB,CACf;QACE,aAAa;QACb,SAAS;QACT,IAAI,EAAE,6BAA6B;KACpC,EACD,CAAC,EAAE,EAAE,EAAE;QACL,EAAE,CAAC,WAAW,KAAd,EAAE,CAAC,WAAW,GAAK,EAAE,EAAC;QACtB,EAAE,CAAC,WAAW,CAAC,IAAI,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAC5D,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,6BAA6B,EAAE;QACjC,OAAO;QACP,YAAY;QACZ,aAAa;KACd,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC;QACzC,SAAS;QACT,SAAS,EAAE,OAAO;QAClB,YAAY;QACZ,aAAa;QACb,aAAa;KACd,CAAC,CAAC;IAEH,GAAG,CAAC,sBAAsB,EAAE;QAC1B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,OAAO;QACP,aAAa;KACd,CAAC,CAAC;IAEH,OAAO,MAAM,8BAA8B,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,mBAAmB,CAAC,QAA4B;IACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC1B,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,kBAAkB,CAAC,EAC1B,aAAa,EACb,WAAW,EACX,aAAa,GAKd;IACC,MAAM,YAAY,GAAG,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IACzD,MAAM,eAAe,GAAG,kBAAkB,CACxC,aAAa,CAAC,OAAO,EACrB,aAAa,CAAC,OAAO,CACtB,CAAC,WAAW,EAAE,CAAC;IAChB,MAAM,eAAe,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAEzD,IAAI,YAAY,IAAI,YAAY,KAAK,eAAe,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,6CAA6C,aAAa,IAAI;YAC5D,YAAY,eAAe,SAAS,YAAY,EAAE,CACrD,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,IAAI,YAAY,KAAK,eAAe,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,6CAA6C,aAAa,IAAI;YAC5D,YAAY,eAAe,SAAS,YAAY,EAAE,CACrD,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,qBAAqB,CAAC,EAC7B,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GAKd;IACC,MAAM,QAAQ,GAAG,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAElD,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO;IACT,CAAC;IAED,MAAM,eAAe,GAAG,QAAQ;SAC7B,KAAK,CAAC,QAAQ,CAAC;SACf,SAAS,CAAC,QAAQ,CAAC;SACnB,YAAY,CAAC,GAAG,CAAC,CAAC;IAErB,GAAG,CAAC,sBAAsB,EAAE;QAC1B,iBAAiB;QACjB,iBAAiB;QACjB,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3C,aAAa;KACd,CAAC,CAAC;IAEH,IAAI,eAAe,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,mDAAmD;YACjD,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,oBAAoB,OAAO,CACxE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,sBAAsB,CAAC,EACpC,SAAS,EACT,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,GAOd;IACC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,UAA8B,CAAC;IAEnC,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,KAA6B,CAAC;QAElC,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAC1B,0BAA0B,EAC1B,YAAY,EACZ,SAAS,EACT,aAAa,CACd,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACV,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;YAE1B,GAAG,CAAC,mBAAmB,EAAE;gBACvB,WAAW,EAAE,KAAK,CAAC,MAAM;gBACzB,YAAY;gBACZ,aAAa;aACd,CAAC,CAAC;YAEH,IAAI,KAAK,CAAC,MAAM,KAAK,gBAAgB,CAAC,SAAS,EAAE,CAAC;gBAChD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,IAAI,yBAAyB,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CAAC,cAAc,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,qBAAqB,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CACb,8CAA8C,UAAU,GAAG,CAC5D,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,8BAA8B,CAAC,EAC5C,KAAK,EACL,OAAO,GAIR;IACC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACnD,MAAM,aAAa,GAAG,WAAW,CAAC,EAAE,CAAC;IAErC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,SAAS,GAAG,6BAA6B,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAExE,kBAAkB,CAAC;QACjB,aAAa,EAAE,SAAS;QACxB,WAAW,EAAE,KAAK,CAAC,cAAc;QACjC,aAAa;KACd,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAW,CAAC;IAEvD,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAAC;QACnD,SAAS;QACT,KAAK;QACL,SAAS;QACT,aAAa;KACd,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACtC,MAAM,YAAY,GAAiB;QACjC,GAAG,WAAW;QACd,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,KAAK;QAClB,gBAAgB,EAAE,eAAe;QACjC,iBAAiB,EAAE,eAAe;KACnC,CAAC;IAEF,GAAG,CAAC,4CAA4C,EAAE;QAChD,oBAAoB,EAAE,KAAK,CAAC,YAAY;QACxC,YAAY;QACZ,eAAe;QACf,aAAa;KACd,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC;QACvC,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;QAChD,SAAS;QACT,QAAQ,EAAE,CAAC,YAAY,CAAC;QACxB,WAAW;KACZ,CAAC,CAAC;IAEH,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;IACzD,qBAAqB,CAAC;QACpB,iBAAiB,EAAE,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM;QAChE,iBAAiB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM;QACrE,aAAa;KACd,CAAC,CAAC;IAEH,GAAG,CAAC,gDAAgD,EAAE;QACpD,eAAe,EAAE,WAAW,CAAC,MAAM;QACnC,aAAa;KACd,CAAC,CAAC;IAEH,MAAM,kBAAkB,GAA0C;QAChE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;QAChD,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;QAC9C,SAAS;QACT,MAAM,EAAE,WAAW;QACnB,WAAW;KACZ,CAAC;IAEF,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IAEhE,GAAG,CAAC,6CAA6C,EAAE;QACjD,WAAW;QACX,aAAa;KACd,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACrB,CAAC","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';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n} from '../../types';\nimport { buildCaipAssetType } from '../../utils/token';\nimport { updateTransaction } from '../../utils/transaction';\nimport { getRelayQuotes } from '../relay/relay-quotes';\nimport { submitRelayQuotes } from '../relay/relay-submit';\nimport type { RelayQuote } from '../relay/types';\nimport type { TransactionPayFiatAsset } from './constants';\nimport type { FiatQuote } from './types';\nimport { deriveFiatAssetForFiatPayment, resolveSourceAmountRaw } from './utils';\n\nconst log = createModuleLogger(projectLogger, 'fiat-submit');\n\nconst ORDER_POLL_INTERVAL_MS = 1000;\nconst ORDER_POLL_TIMEOUT_MS = 10 * 60 * 1000;\nconst MAX_SLIPPAGE_PERCENT = 5;\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 walletAddress = transaction.txParams.from as Hex | undefined;\n\n if (!walletAddress) {\n throw new Error('Missing wallet address for fiat submission');\n }\n\n const state = messenger.call('TransactionPayController:getState');\n const fiatPayment = state.transactionData[transactionId]?.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 * 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 */\nfunction extractProviderCode(provider: string | undefined): 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 * 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 * Validates that the re-quoted relay target output hasn't drifted beyond the\n * acceptable slippage threshold compared to the original quote shown to the user.\n *\n * @param options - The validation options.\n * @param options.originalTargetRaw - Raw target amount from the original relay quote.\n * @param options.reQuotedTargetRaw - Raw target amount from the re-quoted relay.\n * @param options.transactionId - Transaction ID for error reporting.\n */\nfunction validateRelaySlippage({\n originalTargetRaw,\n reQuotedTargetRaw,\n transactionId,\n}: {\n originalTargetRaw: string;\n reQuotedTargetRaw: string;\n transactionId: string;\n}): void {\n const original = new BigNumber(originalTargetRaw);\n const reQuoted = new BigNumber(reQuotedTargetRaw);\n\n if (!original.gt(0) || !reQuoted.gt(0)) {\n return;\n }\n\n const slippagePercent = original\n .minus(reQuoted)\n .dividedBy(original)\n .multipliedBy(100);\n\n log('Relay slippage check', {\n originalTargetRaw,\n reQuotedTargetRaw,\n slippagePercent: slippagePercent.toFixed(2),\n transactionId,\n });\n\n if (slippagePercent.gt(MAX_SLIPPAGE_PERCENT)) {\n throw new Error(\n `Relay re-quote slippage too high for transaction ` +\n `${slippagePercent.toFixed(2)}% exceeds ${MAX_SLIPPAGE_PERCENT}% max`,\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 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 >= ORDER_POLL_TIMEOUT_MS) {\n throw new Error(\n `Fiat order polling timed out (last status: ${lastStatus})`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, ORDER_POLL_INTERVAL_MS));\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 fiatAsset = deriveFiatAssetForFiatPayment(transaction, messenger);\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const walletAddress = transaction.txParams.from as Hex;\n\n const sourceAmountRaw = await resolveSourceAmountRaw({\n messenger,\n order,\n fiatAsset,\n walletAddress,\n });\n\n const baseRequest = quotes[0].request;\n const relayRequest: QuoteRequest = {\n ...baseRequest,\n isMaxAmount: true,\n isPostQuote: false,\n sourceBalanceRaw: sourceAmountRaw,\n sourceTokenAmount: sourceAmountRaw,\n };\n\n log('Re-quoting relay from completed fiat order', {\n completedOrderAmount: order.cryptoAmount,\n relayRequest,\n sourceAmountRaw,\n transactionId,\n });\n\n const relayQuotes = await getRelayQuotes({\n accountSupports7702: request.accountSupports7702,\n messenger,\n requests: [relayRequest],\n transaction,\n });\n\n if (!relayQuotes.length) {\n throw new Error('No relay quotes returned for completed fiat order');\n }\n\n const originalRelayQuote = quotes[0].original.relayQuote;\n validateRelaySlippage({\n originalTargetRaw: originalRelayQuote.details.currencyOut.amount,\n reQuotedTargetRaw: relayQuotes[0].original.details.currencyOut.amount,\n transactionId,\n });\n\n log('Received relay quotes for completed fiat order', {\n relayQuoteCount: relayQuotes.length,\n transactionId,\n });\n\n const relaySubmitRequest: PayStrategyExecuteRequest<RelayQuote> = {\n accountSupports7702: request.accountSupports7702,\n isSmartTransaction: request.isSmartTransaction,\n messenger,\n quotes: relayQuotes,\n transaction,\n };\n\n const relayResult = await submitRelayQuotes(relaySubmitRequest);\n\n log('Relay submission completed after fiat order', {\n relayResult,\n transactionId,\n });\n\n return relayResult;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getRawSourceAmountFromOrderCryptoAmount = exports.resolveSourceAmountRaw = 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");
|
|
@@ -90,69 +90,4 @@ function getRawSourceAmountFromOrderCryptoAmount({ cryptoAmount, decimals, }) {
|
|
|
90
90
|
return rawAmount;
|
|
91
91
|
}
|
|
92
92
|
exports.getRawSourceAmountFromOrderCryptoAmount = getRawSourceAmountFromOrderCryptoAmount;
|
|
93
|
-
/**
|
|
94
|
-
* Validates that the relay exchange rate hasn't drifted significantly between
|
|
95
|
-
* the original quoting phase and the post-settlement discovery quote.
|
|
96
|
-
*
|
|
97
|
-
* Compares the USD output/input ratio from both quotes. This normalises for
|
|
98
|
-
* different source amounts (quoting phase uses a theoretical amount, discovery
|
|
99
|
-
* uses the actual settled amount) so the comparison reflects genuine rate
|
|
100
|
-
* movement rather than amount differences.
|
|
101
|
-
*
|
|
102
|
-
* @param options - The validation options.
|
|
103
|
-
* @param options.originalQuote - Relay quote from the original quoting phase.
|
|
104
|
-
* @param options.discoveryQuote - Relay quote from the post-settlement discovery.
|
|
105
|
-
* @param options.maxRateDriftPercent - Maximum allowed rate drift percentage.
|
|
106
|
-
* @param options.transactionId - Transaction ID for error reporting.
|
|
107
|
-
*/
|
|
108
|
-
function validateRelayRateDrift({ originalQuote, discoveryQuote, maxRateDriftPercent, transactionId, }) {
|
|
109
|
-
const originalIn = new bignumber_js_1.BigNumber(originalQuote.details.currencyIn.amountUsd);
|
|
110
|
-
const originalOut = new bignumber_js_1.BigNumber(originalQuote.details.currencyOut.amountUsd);
|
|
111
|
-
const discoveryIn = new bignumber_js_1.BigNumber(discoveryQuote.details.currencyIn.amountUsd);
|
|
112
|
-
const discoveryOut = new bignumber_js_1.BigNumber(discoveryQuote.details.currencyOut.amountUsd);
|
|
113
|
-
if (!originalIn.gt(0) ||
|
|
114
|
-
!originalOut.gt(0) ||
|
|
115
|
-
!discoveryIn.gt(0) ||
|
|
116
|
-
!discoveryOut.gt(0)) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const originalRate = originalOut.dividedBy(originalIn);
|
|
120
|
-
const discoveryRate = discoveryOut.dividedBy(discoveryIn);
|
|
121
|
-
const driftPercent = originalRate
|
|
122
|
-
.minus(discoveryRate)
|
|
123
|
-
.dividedBy(originalRate)
|
|
124
|
-
.multipliedBy(100);
|
|
125
|
-
log('Relay rate drift check', {
|
|
126
|
-
originalRate: originalRate.toFixed(6),
|
|
127
|
-
discoveryRate: discoveryRate.toFixed(6),
|
|
128
|
-
driftPercent: driftPercent.toFixed(2),
|
|
129
|
-
maxRateDriftPercent,
|
|
130
|
-
transactionId,
|
|
131
|
-
});
|
|
132
|
-
if (driftPercent.gt(maxRateDriftPercent)) {
|
|
133
|
-
throw new Error(`Relay rate drift too high for transaction ` +
|
|
134
|
-
`${driftPercent.toFixed(2)}% exceeds ${maxRateDriftPercent}% max`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
exports.validateRelayRateDrift = validateRelayRateDrift;
|
|
138
|
-
/**
|
|
139
|
-
* Extracts the provider code from a ramps provider string.
|
|
140
|
-
*
|
|
141
|
-
* Accepts the canonical provider code (e.g. `transak-native`) and, for
|
|
142
|
-
* backwards compatibility, the legacy path form (e.g. `/providers/transak-native`).
|
|
143
|
-
*
|
|
144
|
-
* @param provider - Canonical provider code, or legacy provider path.
|
|
145
|
-
* @returns The provider code, or `null` if the format is invalid.
|
|
146
|
-
*/
|
|
147
|
-
function extractProviderCode(provider) {
|
|
148
|
-
if (!provider) {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
const parts = provider.split('/').filter(Boolean);
|
|
152
|
-
if (parts[0] === 'providers') {
|
|
153
|
-
return parts[1] ?? null;
|
|
154
|
-
}
|
|
155
|
-
return parts.length === 1 ? parts[0] : null;
|
|
156
|
-
}
|
|
157
|
-
exports.extractProviderCode = extractProviderCode;
|
|
158
93
|
//# sourceMappingURL=utils.cjs.map
|