@metamask/transaction-pay-controller 20.2.0 → 21.1.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.
- package/CHANGELOG.md +32 -1
- package/dist/TransactionPayController.cjs +25 -0
- package/dist/TransactionPayController.cjs.map +1 -1
- package/dist/TransactionPayController.d.cts.map +1 -1
- package/dist/TransactionPayController.d.mts.map +1 -1
- package/dist/TransactionPayController.mjs +26 -1
- package/dist/TransactionPayController.mjs.map +1 -1
- package/dist/strategy/across/across-quotes.cjs +137 -41
- package/dist/strategy/across/across-quotes.cjs.map +1 -1
- package/dist/strategy/across/across-quotes.d.cts.map +1 -1
- package/dist/strategy/across/across-quotes.d.mts.map +1 -1
- package/dist/strategy/across/across-quotes.mjs +138 -42
- package/dist/strategy/across/across-quotes.mjs.map +1 -1
- package/dist/strategy/across/across-submit.cjs +5 -0
- package/dist/strategy/across/across-submit.cjs.map +1 -1
- package/dist/strategy/across/across-submit.mjs +5 -0
- package/dist/strategy/across/across-submit.mjs.map +1 -1
- package/dist/strategy/fiat/constants.cjs +2 -1
- package/dist/strategy/fiat/constants.cjs.map +1 -1
- package/dist/strategy/fiat/constants.d.cts +1 -0
- package/dist/strategy/fiat/constants.d.cts.map +1 -1
- package/dist/strategy/fiat/constants.d.mts +1 -0
- package/dist/strategy/fiat/constants.d.mts.map +1 -1
- package/dist/strategy/fiat/constants.mjs +1 -0
- package/dist/strategy/fiat/constants.mjs.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.cjs +31 -9
- package/dist/strategy/fiat/fiat-quotes.cjs.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.d.cts.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.d.mts.map +1 -1
- package/dist/strategy/fiat/fiat-quotes.mjs +32 -10
- package/dist/strategy/fiat/fiat-quotes.mjs.map +1 -1
- package/dist/strategy/fiat/fiat-submit.cjs +264 -5
- package/dist/strategy/fiat/fiat-submit.cjs.map +1 -1
- package/dist/strategy/fiat/fiat-submit.d.cts +9 -4
- package/dist/strategy/fiat/fiat-submit.d.cts.map +1 -1
- package/dist/strategy/fiat/fiat-submit.d.mts +9 -4
- package/dist/strategy/fiat/fiat-submit.d.mts.map +1 -1
- package/dist/strategy/fiat/fiat-submit.mjs +264 -5
- package/dist/strategy/fiat/fiat-submit.mjs.map +1 -1
- package/dist/strategy/fiat/types.cjs.map +1 -1
- package/dist/strategy/fiat/types.d.cts +1 -2
- package/dist/strategy/fiat/types.d.cts.map +1 -1
- package/dist/strategy/fiat/types.d.mts +1 -2
- package/dist/strategy/fiat/types.d.mts.map +1 -1
- package/dist/strategy/fiat/types.mjs.map +1 -1
- package/dist/strategy/fiat/utils.cjs +1 -7
- package/dist/strategy/fiat/utils.cjs.map +1 -1
- package/dist/strategy/fiat/utils.d.cts +0 -2
- package/dist/strategy/fiat/utils.d.cts.map +1 -1
- package/dist/strategy/fiat/utils.d.mts +0 -2
- package/dist/strategy/fiat/utils.d.mts.map +1 -1
- package/dist/strategy/fiat/utils.mjs +0 -5
- package/dist/strategy/fiat/utils.mjs.map +1 -1
- package/dist/strategy/relay/relay-max-gas-station.cjs +1 -1
- package/dist/strategy/relay/relay-max-gas-station.cjs.map +1 -1
- package/dist/strategy/relay/relay-max-gas-station.mjs +1 -1
- package/dist/strategy/relay/relay-max-gas-station.mjs.map +1 -1
- package/dist/strategy/relay/relay-quotes.cjs +8 -5
- package/dist/strategy/relay/relay-quotes.cjs.map +1 -1
- package/dist/strategy/relay/relay-quotes.d.cts.map +1 -1
- package/dist/strategy/relay/relay-quotes.d.mts.map +1 -1
- package/dist/strategy/relay/relay-quotes.mjs +8 -5
- package/dist/strategy/relay/relay-quotes.mjs.map +1 -1
- package/dist/types.cjs +2 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +12 -7
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +12 -7
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +2 -1
- package/dist/types.mjs.map +1 -1
- package/dist/{strategy/relay → utils}/gas-station.cjs +4 -4
- package/dist/{strategy/relay/gas-station.mjs.map → utils/gas-station.cjs.map} +1 -1
- package/dist/{strategy/relay → utils}/gas-station.d.cts +1 -1
- package/dist/utils/gas-station.d.cts.map +1 -0
- package/dist/{strategy/relay → utils}/gas-station.d.mts +1 -1
- package/dist/utils/gas-station.d.mts.map +1 -0
- package/dist/{strategy/relay → utils}/gas-station.mjs +4 -4
- package/dist/utils/gas-station.mjs.map +1 -0
- package/package.json +6 -6
- package/dist/strategy/relay/gas-station.cjs.map +0 -1
- package/dist/strategy/relay/gas-station.d.cts.map +0 -1
- package/dist/strategy/relay/gas-station.d.mts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fiat-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/fiat-submit.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAA8C;IAE9C,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;AACxC,CAAC","sourcesContent":["import type { PayStrategy, PayStrategyExecuteRequest } from '../../types';\nimport type { FiatQuote } from './types';\n\n/**\n * Submit Fiat quotes.\n *\n * @param _request - Strategy execute request.\n * @returns Empty transaction hash until fiat submit implementation is added.\n */\nexport async function submitFiatQuotes(\n _request: PayStrategyExecuteRequest<FiatQuote>,\n): ReturnType<PayStrategy<FiatQuote>['execute']> {\n return { transactionHash: undefined };\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';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n} from '../../types';\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 } 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 orderId = state.transactionData[transactionId]?.fiatPayment?.orderId;\n\n if (!orderId) {\n throw new Error('Missing order ID for fiat submission');\n }\n\n const parsedOrder = parseOrderId(orderId);\n\n if (!parsedOrder) {\n throw new Error(`Invalid order ID format: ${orderId}`);\n }\n\n log('Starting fiat order polling', {\n orderId,\n providerCode: parsedOrder.providerCode,\n transactionId,\n });\n\n const order = await waitForOrderCompletion({\n messenger,\n orderCode: parsedOrder.orderCode,\n providerCode: parsedOrder.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 * Parses a normalized order ID string into its provider and order components.\n *\n * @param orderId - Order ID in `/providers/{providerCode}/orders/{orderCode}` format.\n * @returns The parsed provider and order codes, or `null` if the format is invalid.\n */\nfunction parseOrderId(\n orderId: string,\n): { orderCode: string; providerCode: string } | null {\n const parts = orderId.split('/').filter(Boolean);\n\n if (parts.length < 4 || parts[0] !== 'providers' || parts[2] !== 'orders') {\n return null;\n }\n\n return { orderCode: parts[3], providerCode: parts[1] };\n}\n\n/**\n * Converts the order's human-readable crypto amount to a raw token amount.\n *\n * @param options - The conversion options.\n * @param options.cryptoAmount - Human-readable crypto amount from the completed order.\n * @param options.decimals - Token decimals for the fiat asset.\n * @returns The raw token amount as a string.\n */\nfunction getRawSourceAmountFromOrder({\n cryptoAmount,\n decimals,\n}: {\n cryptoAmount: RampsOrder['cryptoAmount'];\n decimals: number;\n}): string {\n const normalizedAmount = new BigNumber(String(cryptoAmount));\n\n if (!normalizedAmount.isFinite() || normalizedAmount.lte(0)) {\n throw new Error(\n `Invalid fiat order crypto amount: ${String(cryptoAmount)}`,\n );\n }\n\n const rawAmount = normalizedAmount\n .shiftedBy(decimals)\n .decimalPlaces(0, BigNumber.ROUND_DOWN)\n .toFixed(0);\n\n if (!new BigNumber(rawAmount).gt(0)) {\n throw new Error('Computed fiat order source amount is not positive');\n }\n\n return rawAmount;\n}\n\n/**\n * Validates that the 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 = expectedAsset.caipAssetId.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);\n if (!fiatAsset) {\n throw new Error(\n `Missing fiat asset mapping for transaction type: ${String(transaction.type)}`,\n );\n }\n\n validateOrderAsset({\n expectedAsset: fiatAsset,\n orderCrypto: order.cryptoCurrency,\n transactionId,\n });\n\n const sourceAmountRaw = getRawSourceAmountFromOrder({\n cryptoAmount: order.cryptoAmount,\n decimals: fiatAsset.decimals,\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":"types.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Quote
|
|
1
|
+
{"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Quote } from '@metamask/ramps-controller';\n\nimport type { RelayQuote } from '../relay/types';\n\nexport type FiatQuote = {\n rampsQuote: Quote;\n relayQuote: RelayQuote;\n};\n"]}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { Quote
|
|
1
|
+
import type { Quote } from "@metamask/ramps-controller";
|
|
2
2
|
import type { RelayQuote } from "../relay/types.cjs";
|
|
3
3
|
export type FiatQuote = {
|
|
4
4
|
rampsQuote: Quote;
|
|
5
5
|
relayQuote: RelayQuote;
|
|
6
6
|
};
|
|
7
|
-
export type FiatQuotesResponse = QuotesResponse;
|
|
8
7
|
//# sourceMappingURL=types.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,mCAAmC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,2BAAuB;AAEjD,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,EAAE,KAAK,CAAC;IAClB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { Quote
|
|
1
|
+
import type { Quote } from "@metamask/ramps-controller";
|
|
2
2
|
import type { RelayQuote } from "../relay/types.mjs";
|
|
3
3
|
export type FiatQuote = {
|
|
4
4
|
rampsQuote: Quote;
|
|
5
5
|
relayQuote: RelayQuote;
|
|
6
6
|
};
|
|
7
|
-
export type FiatQuotesResponse = QuotesResponse;
|
|
8
7
|
//# sourceMappingURL=types.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,mCAAmC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,2BAAuB;AAEjD,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,EAAE,KAAK,CAAC;IAClB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Quote
|
|
1
|
+
{"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Quote } from '@metamask/ramps-controller';\n\nimport type { RelayQuote } from '../relay/types';\n\nexport type FiatQuote = {\n rampsQuote: Quote;\n relayQuote: RelayQuote;\n};\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.deriveFiatAssetForFiatPayment = void 0;
|
|
4
4
|
const transaction_controller_1 = require("@metamask/transaction-controller");
|
|
5
5
|
const constants_1 = require("./constants.cjs");
|
|
6
6
|
function deriveFiatAssetForFiatPayment(transaction) {
|
|
@@ -14,10 +14,4 @@ function deriveFiatAssetForFiatPayment(transaction) {
|
|
|
14
14
|
return constants_1.FIAT_ASSET_ID_BY_TX_TYPE[transactionType];
|
|
15
15
|
}
|
|
16
16
|
exports.deriveFiatAssetForFiatPayment = deriveFiatAssetForFiatPayment;
|
|
17
|
-
function pickBestFiatQuote(quotes) {
|
|
18
|
-
return quotes.success?.find(
|
|
19
|
-
// TODO: Implement provider selection logic; force Transak staging for now.
|
|
20
|
-
(quote) => quote.provider === '/providers/transak-native-staging');
|
|
21
|
-
}
|
|
22
|
-
exports.pickBestFiatQuote = pickBestFiatQuote;
|
|
23
17
|
//# sourceMappingURL=utils.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":";;;AAAA,6EAG0C;AAE1C,+CAAgF;AAEhF,SAAgB,6BAA6B,CAC3C,WAA4B;IAE5B,MAAM,eAAe,GAAG,WAAW,EAAE,IAAI,CAAC;IAE1C,IAAI,eAAe,KAAK,wCAAe,CAAC,KAAK,EAAE,CAAC;QAC9C,MAAM,iBAAiB,GAAG,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QACpE,IAAI,iBAAiB,EAAE,CAAC;YACtB,OAAO,oCAAwB,CAAC,iBAAiB,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,OAAO,oCAAwB,CAAC,eAAkC,CAAC,CAAC;AACtE,CAAC;AAbD,sEAaC","sourcesContent":["import {\n TransactionMeta,\n TransactionType,\n} from '@metamask/transaction-controller';\n\nimport { FIAT_ASSET_ID_BY_TX_TYPE, TransactionPayFiatAsset } from './constants';\n\nexport function deriveFiatAssetForFiatPayment(\n transaction: TransactionMeta,\n): TransactionPayFiatAsset | undefined {\n const transactionType = transaction?.type;\n\n if (transactionType === TransactionType.batch) {\n const firstMatchingType = transaction.nestedTransactions?.[0]?.type;\n if (firstMatchingType) {\n return FIAT_ASSET_ID_BY_TX_TYPE[firstMatchingType];\n }\n }\n\n return FIAT_ASSET_ID_BY_TX_TYPE[transactionType as TransactionType];\n}\n"]}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type { Quote as RampsQuote, QuotesResponse as RampsQuotesResponse } from "@metamask/ramps-controller";
|
|
2
1
|
import { TransactionMeta } from "@metamask/transaction-controller";
|
|
3
2
|
import { TransactionPayFiatAsset } from "./constants.cjs";
|
|
4
3
|
export declare function deriveFiatAssetForFiatPayment(transaction: TransactionMeta): TransactionPayFiatAsset | undefined;
|
|
5
|
-
export declare function pickBestFiatQuote(quotes: RampsQuotesResponse): RampsQuote | undefined;
|
|
6
4
|
//# sourceMappingURL=utils.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEhB,yCAAyC;AAE1C,OAAO,EAA4B,uBAAuB,EAAE,wBAAoB;AAEhF,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,eAAe,GAC3B,uBAAuB,GAAG,SAAS,CAWrC"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type { Quote as RampsQuote, QuotesResponse as RampsQuotesResponse } from "@metamask/ramps-controller";
|
|
2
1
|
import { TransactionMeta } from "@metamask/transaction-controller";
|
|
3
2
|
import { TransactionPayFiatAsset } from "./constants.mjs";
|
|
4
3
|
export declare function deriveFiatAssetForFiatPayment(transaction: TransactionMeta): TransactionPayFiatAsset | undefined;
|
|
5
|
-
export declare function pickBestFiatQuote(quotes: RampsQuotesResponse): RampsQuote | undefined;
|
|
6
4
|
//# sourceMappingURL=utils.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEhB,yCAAyC;AAE1C,OAAO,EAA4B,uBAAuB,EAAE,wBAAoB;AAEhF,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,eAAe,GAC3B,uBAAuB,GAAG,SAAS,CAWrC"}
|
|
@@ -10,9 +10,4 @@ export function deriveFiatAssetForFiatPayment(transaction) {
|
|
|
10
10
|
}
|
|
11
11
|
return FIAT_ASSET_ID_BY_TX_TYPE[transactionType];
|
|
12
12
|
}
|
|
13
|
-
export function pickBestFiatQuote(quotes) {
|
|
14
|
-
return quotes.success?.find(
|
|
15
|
-
// TODO: Implement provider selection logic; force Transak staging for now.
|
|
16
|
-
(quote) => quote.provider === '/providers/transak-native-staging');
|
|
17
|
-
}
|
|
18
13
|
//# sourceMappingURL=utils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../../src/strategy/fiat/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAChB,yCAAyC;AAE1C,OAAO,EAAE,wBAAwB,EAA2B,wBAAoB;AAEhF,MAAM,UAAU,6BAA6B,CAC3C,WAA4B;IAE5B,MAAM,eAAe,GAAG,WAAW,EAAE,IAAI,CAAC;IAE1C,IAAI,eAAe,KAAK,eAAe,CAAC,KAAK,EAAE,CAAC;QAC9C,MAAM,iBAAiB,GAAG,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QACpE,IAAI,iBAAiB,EAAE,CAAC;YACtB,OAAO,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,OAAO,wBAAwB,CAAC,eAAkC,CAAC,CAAC;AACtE,CAAC","sourcesContent":["import {\n TransactionMeta,\n TransactionType,\n} from '@metamask/transaction-controller';\n\nimport { FIAT_ASSET_ID_BY_TX_TYPE, TransactionPayFiatAsset } from './constants';\n\nexport function deriveFiatAssetForFiatPayment(\n transaction: TransactionMeta,\n): TransactionPayFiatAsset | undefined {\n const transactionType = transaction?.type;\n\n if (transactionType === TransactionType.batch) {\n const firstMatchingType = transaction.nestedTransactions?.[0]?.type;\n if (firstMatchingType) {\n return FIAT_ASSET_ID_BY_TX_TYPE[firstMatchingType];\n }\n }\n\n return FIAT_ASSET_ID_BY_TX_TYPE[transactionType as TransactionType];\n}\n"]}
|
|
@@ -4,8 +4,8 @@ exports.getRelayMaxGasStationQuote = void 0;
|
|
|
4
4
|
const utils_1 = require("@metamask/utils");
|
|
5
5
|
const bignumber_js_1 = require("bignumber.js");
|
|
6
6
|
const logger_1 = require("../../logger.cjs");
|
|
7
|
+
const gas_station_1 = require("../../utils/gas-station.cjs");
|
|
7
8
|
const token_1 = require("../../utils/token.cjs");
|
|
8
|
-
const gas_station_1 = require("./gas-station.cjs");
|
|
9
9
|
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'relay-max-gas-station');
|
|
10
10
|
const PROBE_AMOUNT_PERCENTAGE = 0.25;
|
|
11
11
|
var GasCostEstimateSource;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-max-gas-station.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-max-gas-station.ts"],"names":[],"mappings":"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","sourcesContent":["import { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenInfo,\n} from '../../utils/token';\nimport {\n getGasStationEligibility,\n getGasStationCostInSourceTokenRaw,\n} from './gas-station';\nimport type { RelayQuote, RelayTransactionStep } from './types';\n\nconst log = createModuleLogger(projectLogger, 'relay-max-gas-station');\n\nconst PROBE_AMOUNT_PERCENTAGE = 0.25;\n\nenum GasCostEstimateSource {\n GasStation = 'gas-station',\n Probe = 'probe',\n Quote = 'quote',\n}\n\ntype GasCostEstimate = {\n amount: BigNumber;\n source: GasCostEstimateSource;\n};\n\ntype NativeBalanceCheckResult = {\n hasEnoughNativeBalance: boolean;\n nativeBalance?: string;\n nativeGasCostRaw?: string;\n};\n\ntype GetSingleQuoteFn = (\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n) => Promise<TransactionPayQuote<RelayQuote>>;\n\ntype MaxAmountQuoteContext = {\n fullRequest: PayStrategyGetQuotesRequest;\n getSingleQuote: GetSingleQuoteFn;\n messenger: TransactionPayControllerMessenger;\n request: QuoteRequest;\n};\n\n/**\n * Returns a Relay max-amount quote using a two-phase gas-station fallback.\n *\n * It first requests a standard max quote (phase 1), then when needed estimates\n * gas in source-token units (directly or via a probe quote), requests an\n * adjusted max quote (phase 2), and accepts phase 2 only if validation passes\n * (source gas fee token selected, gas-limit checks, affordability).\n *\n * If any step fails or validation is unsafe, it safely falls back to phase 1.\n * Successful phase-2 quotes are tagged with `metamask.isMaxGasStation = true`.\n *\n * @param request - Relay quote request for a max-amount flow.\n * @param fullRequest - Full quote request context including messenger and transaction.\n * @param getSingleQuote - Quote fetcher used for phase-1, phase-2, and probe quotes.\n * @returns The validated adjusted phase-2 quote, or the original phase-1 quote on fallback.\n */\nexport async function getRelayMaxGasStationQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n getSingleQuote: GetSingleQuoteFn,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n const { sourceChainId, sourceTokenAmount } = request;\n const context: MaxAmountQuoteContext = {\n fullRequest,\n getSingleQuote,\n messenger,\n request,\n };\n\n const phase1Quote = await getSingleQuote(request, fullRequest);\n\n const nativeBalanceCheck = checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n phase1Quote,\n messenger,\n request,\n );\n\n if (nativeBalanceCheck.hasEnoughNativeBalance) {\n return fallbackToPhase1(\n phase1Quote,\n 'Native balance is sufficient for gas',\n {\n nativeBalance: nativeBalanceCheck.nativeBalance,\n nativeGasCost: nativeBalanceCheck.nativeGasCostRaw,\n },\n );\n }\n\n const gasStationEligibility = getGasStationEligibility(\n messenger,\n sourceChainId,\n );\n\n if (!gasStationEligibility.isEligible) {\n return fallbackToPhase1(\n phase1Quote,\n 'Gas station is disabled or unsupported',\n );\n }\n\n const sourceAmountBN = new BigNumber(sourceTokenAmount);\n const probeCost = await getProbeGasCostInSourceTokenRaw(context);\n\n if (!probeCost) {\n return fallbackToPhase1(\n phase1Quote,\n 'Unable to estimate gas-station source token cost',\n );\n }\n\n const initialGasEstimate: GasCostEstimate = {\n amount: probeCost,\n source: GasCostEstimateSource.Probe,\n };\n\n const adjustedSourceAmount = getAdjustedSourceAmount(\n sourceAmountBN,\n initialGasEstimate.amount,\n );\n\n if (!adjustedSourceAmount.isGreaterThan(0)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Insufficient balance for gas station after max adjustment',\n );\n }\n\n const phase2Quote = await getAdjustedPhase2Quote(\n adjustedSourceAmount,\n initialGasEstimate,\n context,\n );\n\n if (!phase2Quote) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted phase-2 quote request failed',\n );\n }\n\n if (!phase2Quote.fees.isSourceGasFeeToken) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote did not return source gas fee token pricing',\n );\n }\n\n const phase1GasLimits = phase1Quote.original.metamask.gasLimits ?? [];\n const phase2GasLimits = phase2Quote.original.metamask.gasLimits ?? [];\n\n if (!hasMatchingGasLimitShape(phase1GasLimits, phase2GasLimits)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote gas limit shape changed between phases',\n {\n phase1GasLimits,\n phase2GasLimits,\n },\n );\n }\n\n const phase1TotalGasLimit = getTotalGasLimit(phase1GasLimits);\n const phase2TotalGasLimit = getTotalGasLimit(phase2GasLimits);\n\n if (phase2TotalGasLimit > phase1TotalGasLimit) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote total gas limit increased between phases',\n {\n phase1TotalGasLimit,\n phase2TotalGasLimit,\n },\n );\n }\n\n const validationGasEstimate = new BigNumber(\n phase2Quote.fees.sourceNetwork.max.raw,\n );\n\n if (\n !isAdjustedAmountAffordable(\n adjustedSourceAmount,\n validationGasEstimate,\n sourceAmountBN,\n )\n ) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote fails affordability validation',\n {\n adjustedSourceAmount: adjustedSourceAmount.toString(10),\n validationGasCost: validationGasEstimate.toString(10),\n },\n );\n }\n\n markQuoteAsMaxGasStation(phase2Quote);\n\n return phase2Quote;\n}\n\nfunction checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): NativeBalanceCheckResult {\n if (quote.fees.isSourceGasFeeToken) {\n return { hasEnoughNativeBalance: false };\n }\n\n const nativeGasCostRaw = quote.fees.sourceNetwork.max.raw;\n const nativeBalance = getTokenBalance(\n messenger,\n request.from,\n request.sourceChainId,\n getNativeToken(request.sourceChainId),\n );\n\n return {\n hasEnoughNativeBalance: new BigNumber(nativeBalance).isGreaterThanOrEqualTo(\n nativeGasCostRaw,\n ),\n nativeBalance,\n nativeGasCostRaw,\n };\n}\n\nfunction getAdjustedSourceAmount(\n sourceAmount: BigNumber,\n estimatedGasCost: BigNumber,\n): BigNumber {\n return sourceAmount\n .minus(estimatedGasCost)\n .integerValue(BigNumber.ROUND_DOWN);\n}\n\nfunction isAdjustedAmountAffordable(\n adjustedSourceAmount: BigNumber,\n gasCost: BigNumber,\n originalSourceAmount: BigNumber,\n): boolean {\n return adjustedSourceAmount\n .plus(gasCost)\n .isLessThanOrEqualTo(originalSourceAmount);\n}\n\nasync function getAdjustedPhase2Quote(\n adjustedSourceAmount: BigNumber,\n initialGasEstimate: GasCostEstimate,\n context: MaxAmountQuoteContext,\n): Promise<TransactionPayQuote<RelayQuote> | undefined> {\n const { fullRequest, getSingleQuote, request } = context;\n\n log('Requesting adjusted max quote', {\n adjustedAmount: adjustedSourceAmount.toString(10),\n gasCostInSourceToken: initialGasEstimate.amount.toString(10),\n gasEstimateSource: initialGasEstimate.source,\n originalAmount: request.sourceTokenAmount,\n });\n\n try {\n return await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: adjustedSourceAmount.toFixed(\n 0,\n BigNumber.ROUND_DOWN,\n ),\n },\n fullRequest,\n );\n } catch (error) {\n log('Adjusted quote request failed, falling back to phase-1 quote', {\n error,\n });\n return undefined;\n }\n}\n\nasync function getGasCostFromQuoteOrGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): Promise<GasCostEstimate | undefined> {\n const gasCost = quote.fees.sourceNetwork.max;\n\n if (quote.fees.isSourceGasFeeToken) {\n log('Gas cost already in source token units', { raw: gasCost.raw });\n return {\n amount: new BigNumber(gasCost.raw),\n source: GasCostEstimateSource.Quote,\n };\n }\n\n const firstTxStep = quote.original.steps.find(\n (step): step is RelayTransactionStep => step.kind === 'transaction',\n );\n const firstStepData = firstTxStep?.items[0]?.data;\n\n if (!firstStepData) {\n return undefined;\n }\n\n const totalItemCount = quote.original.steps.reduce(\n (count, step) => count + step.items.length,\n 0,\n );\n\n const totalGasEstimate = (quote.original.metamask.gasLimits ?? []).reduce(\n (acc, gasLimit) => acc + gasLimit,\n 0,\n );\n\n const gasStationCost = await getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request: {\n from: request.from,\n sourceChainId: request.sourceChainId,\n sourceTokenAddress: request.sourceTokenAddress,\n },\n totalGasEstimate,\n totalItemCount,\n });\n\n if (!gasStationCost) {\n return undefined;\n }\n\n return {\n amount: new BigNumber(gasStationCost.raw),\n source: GasCostEstimateSource.GasStation,\n };\n}\n\nasync function getProbeGasCostInSourceTokenRaw(\n context: MaxAmountQuoteContext,\n): Promise<BigNumber | undefined> {\n const { fullRequest, getSingleQuote, messenger, request } = context;\n\n const sourceTokenInfo = getTokenInfo(\n messenger,\n request.sourceTokenAddress,\n request.sourceChainId,\n );\n\n if (!sourceTokenInfo) {\n return undefined;\n }\n\n const probeAmount = getProbeSourceAmountRaw(\n request.sourceTokenAmount,\n sourceTokenInfo.decimals,\n );\n\n if (!probeAmount || probeAmount === request.sourceTokenAmount) {\n return undefined;\n }\n\n log('Requesting probe quote for gas station estimation', {\n originalSourceAmount: request.sourceTokenAmount,\n probeAmount,\n });\n\n let probeQuote: TransactionPayQuote<RelayQuote> | undefined;\n\n try {\n probeQuote = await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: probeAmount,\n },\n fullRequest,\n );\n } catch (error) {\n log('Probe quote request failed', { error });\n return undefined;\n }\n\n if (!probeQuote) {\n return undefined;\n }\n\n const probeEstimate = await getGasCostFromQuoteOrGasStation(\n probeQuote,\n messenger,\n request,\n );\n\n return probeEstimate?.amount;\n}\n\nfunction getProbeSourceAmountRaw(\n sourceAmountRaw: string,\n sourceDecimals: number,\n): string | undefined {\n const sourceAmount = new BigNumber(sourceAmountRaw);\n\n if (sourceAmount.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n const probeRawAmount = sourceAmount\n .multipliedBy(PROBE_AMOUNT_PERCENTAGE)\n .integerValue(BigNumber.ROUND_FLOOR);\n\n // Minimum probe size: ~0.01 token for tokens with >=2 decimals,\n // otherwise one raw unit for low-decimal tokens.\n const minimumProbeRaw = new BigNumber(1).shiftedBy(\n Math.max(sourceDecimals - 2, 0),\n );\n\n const probeRaw = BigNumber.minimum(\n sourceAmount,\n BigNumber.maximum(probeRawAmount, minimumProbeRaw),\n ).integerValue(BigNumber.ROUND_FLOOR);\n\n if (probeRaw.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n return probeRaw.toFixed(0);\n}\n\nfunction fallbackToPhase1(\n phase1Quote: TransactionPayQuote<RelayQuote>,\n message: string,\n paramsToLog?: Record<string, unknown>,\n): TransactionPayQuote<RelayQuote> {\n log(message, paramsToLog);\n return phase1Quote;\n}\n\nfunction hasMatchingGasLimitShape(phase1: number[], phase2: number[]): boolean {\n return phase1.length === phase2.length;\n}\n\nfunction getTotalGasLimit(gasLimits: number[]): number {\n return gasLimits.reduce((total, gasLimit) => total + gasLimit, 0);\n}\n\nfunction markQuoteAsMaxGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n): void {\n quote.original.metamask = {\n ...quote.original.metamask,\n isMaxGasStation: true,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"relay-max-gas-station.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-max-gas-station.ts"],"names":[],"mappings":"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","sourcesContent":["import { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport {\n getGasStationEligibility,\n getGasStationCostInSourceTokenRaw,\n} from '../../utils/gas-station';\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenInfo,\n} from '../../utils/token';\nimport type { RelayQuote, RelayTransactionStep } from './types';\n\nconst log = createModuleLogger(projectLogger, 'relay-max-gas-station');\n\nconst PROBE_AMOUNT_PERCENTAGE = 0.25;\n\nenum GasCostEstimateSource {\n GasStation = 'gas-station',\n Probe = 'probe',\n Quote = 'quote',\n}\n\ntype GasCostEstimate = {\n amount: BigNumber;\n source: GasCostEstimateSource;\n};\n\ntype NativeBalanceCheckResult = {\n hasEnoughNativeBalance: boolean;\n nativeBalance?: string;\n nativeGasCostRaw?: string;\n};\n\ntype GetSingleQuoteFn = (\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n) => Promise<TransactionPayQuote<RelayQuote>>;\n\ntype MaxAmountQuoteContext = {\n fullRequest: PayStrategyGetQuotesRequest;\n getSingleQuote: GetSingleQuoteFn;\n messenger: TransactionPayControllerMessenger;\n request: QuoteRequest;\n};\n\n/**\n * Returns a Relay max-amount quote using a two-phase gas-station fallback.\n *\n * It first requests a standard max quote (phase 1), then when needed estimates\n * gas in source-token units (directly or via a probe quote), requests an\n * adjusted max quote (phase 2), and accepts phase 2 only if validation passes\n * (source gas fee token selected, gas-limit checks, affordability).\n *\n * If any step fails or validation is unsafe, it safely falls back to phase 1.\n * Successful phase-2 quotes are tagged with `metamask.isMaxGasStation = true`.\n *\n * @param request - Relay quote request for a max-amount flow.\n * @param fullRequest - Full quote request context including messenger and transaction.\n * @param getSingleQuote - Quote fetcher used for phase-1, phase-2, and probe quotes.\n * @returns The validated adjusted phase-2 quote, or the original phase-1 quote on fallback.\n */\nexport async function getRelayMaxGasStationQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n getSingleQuote: GetSingleQuoteFn,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n const { sourceChainId, sourceTokenAmount } = request;\n const context: MaxAmountQuoteContext = {\n fullRequest,\n getSingleQuote,\n messenger,\n request,\n };\n\n const phase1Quote = await getSingleQuote(request, fullRequest);\n\n const nativeBalanceCheck = checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n phase1Quote,\n messenger,\n request,\n );\n\n if (nativeBalanceCheck.hasEnoughNativeBalance) {\n return fallbackToPhase1(\n phase1Quote,\n 'Native balance is sufficient for gas',\n {\n nativeBalance: nativeBalanceCheck.nativeBalance,\n nativeGasCost: nativeBalanceCheck.nativeGasCostRaw,\n },\n );\n }\n\n const gasStationEligibility = getGasStationEligibility(\n messenger,\n sourceChainId,\n );\n\n if (!gasStationEligibility.isEligible) {\n return fallbackToPhase1(\n phase1Quote,\n 'Gas station is disabled or unsupported',\n );\n }\n\n const sourceAmountBN = new BigNumber(sourceTokenAmount);\n const probeCost = await getProbeGasCostInSourceTokenRaw(context);\n\n if (!probeCost) {\n return fallbackToPhase1(\n phase1Quote,\n 'Unable to estimate gas-station source token cost',\n );\n }\n\n const initialGasEstimate: GasCostEstimate = {\n amount: probeCost,\n source: GasCostEstimateSource.Probe,\n };\n\n const adjustedSourceAmount = getAdjustedSourceAmount(\n sourceAmountBN,\n initialGasEstimate.amount,\n );\n\n if (!adjustedSourceAmount.isGreaterThan(0)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Insufficient balance for gas station after max adjustment',\n );\n }\n\n const phase2Quote = await getAdjustedPhase2Quote(\n adjustedSourceAmount,\n initialGasEstimate,\n context,\n );\n\n if (!phase2Quote) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted phase-2 quote request failed',\n );\n }\n\n if (!phase2Quote.fees.isSourceGasFeeToken) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote did not return source gas fee token pricing',\n );\n }\n\n const phase1GasLimits = phase1Quote.original.metamask.gasLimits ?? [];\n const phase2GasLimits = phase2Quote.original.metamask.gasLimits ?? [];\n\n if (!hasMatchingGasLimitShape(phase1GasLimits, phase2GasLimits)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote gas limit shape changed between phases',\n {\n phase1GasLimits,\n phase2GasLimits,\n },\n );\n }\n\n const phase1TotalGasLimit = getTotalGasLimit(phase1GasLimits);\n const phase2TotalGasLimit = getTotalGasLimit(phase2GasLimits);\n\n if (phase2TotalGasLimit > phase1TotalGasLimit) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote total gas limit increased between phases',\n {\n phase1TotalGasLimit,\n phase2TotalGasLimit,\n },\n );\n }\n\n const validationGasEstimate = new BigNumber(\n phase2Quote.fees.sourceNetwork.max.raw,\n );\n\n if (\n !isAdjustedAmountAffordable(\n adjustedSourceAmount,\n validationGasEstimate,\n sourceAmountBN,\n )\n ) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote fails affordability validation',\n {\n adjustedSourceAmount: adjustedSourceAmount.toString(10),\n validationGasCost: validationGasEstimate.toString(10),\n },\n );\n }\n\n markQuoteAsMaxGasStation(phase2Quote);\n\n return phase2Quote;\n}\n\nfunction checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): NativeBalanceCheckResult {\n if (quote.fees.isSourceGasFeeToken) {\n return { hasEnoughNativeBalance: false };\n }\n\n const nativeGasCostRaw = quote.fees.sourceNetwork.max.raw;\n const nativeBalance = getTokenBalance(\n messenger,\n request.from,\n request.sourceChainId,\n getNativeToken(request.sourceChainId),\n );\n\n return {\n hasEnoughNativeBalance: new BigNumber(nativeBalance).isGreaterThanOrEqualTo(\n nativeGasCostRaw,\n ),\n nativeBalance,\n nativeGasCostRaw,\n };\n}\n\nfunction getAdjustedSourceAmount(\n sourceAmount: BigNumber,\n estimatedGasCost: BigNumber,\n): BigNumber {\n return sourceAmount\n .minus(estimatedGasCost)\n .integerValue(BigNumber.ROUND_DOWN);\n}\n\nfunction isAdjustedAmountAffordable(\n adjustedSourceAmount: BigNumber,\n gasCost: BigNumber,\n originalSourceAmount: BigNumber,\n): boolean {\n return adjustedSourceAmount\n .plus(gasCost)\n .isLessThanOrEqualTo(originalSourceAmount);\n}\n\nasync function getAdjustedPhase2Quote(\n adjustedSourceAmount: BigNumber,\n initialGasEstimate: GasCostEstimate,\n context: MaxAmountQuoteContext,\n): Promise<TransactionPayQuote<RelayQuote> | undefined> {\n const { fullRequest, getSingleQuote, request } = context;\n\n log('Requesting adjusted max quote', {\n adjustedAmount: adjustedSourceAmount.toString(10),\n gasCostInSourceToken: initialGasEstimate.amount.toString(10),\n gasEstimateSource: initialGasEstimate.source,\n originalAmount: request.sourceTokenAmount,\n });\n\n try {\n return await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: adjustedSourceAmount.toFixed(\n 0,\n BigNumber.ROUND_DOWN,\n ),\n },\n fullRequest,\n );\n } catch (error) {\n log('Adjusted quote request failed, falling back to phase-1 quote', {\n error,\n });\n return undefined;\n }\n}\n\nasync function getGasCostFromQuoteOrGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): Promise<GasCostEstimate | undefined> {\n const gasCost = quote.fees.sourceNetwork.max;\n\n if (quote.fees.isSourceGasFeeToken) {\n log('Gas cost already in source token units', { raw: gasCost.raw });\n return {\n amount: new BigNumber(gasCost.raw),\n source: GasCostEstimateSource.Quote,\n };\n }\n\n const firstTxStep = quote.original.steps.find(\n (step): step is RelayTransactionStep => step.kind === 'transaction',\n );\n const firstStepData = firstTxStep?.items[0]?.data;\n\n if (!firstStepData) {\n return undefined;\n }\n\n const totalItemCount = quote.original.steps.reduce(\n (count, step) => count + step.items.length,\n 0,\n );\n\n const totalGasEstimate = (quote.original.metamask.gasLimits ?? []).reduce(\n (acc, gasLimit) => acc + gasLimit,\n 0,\n );\n\n const gasStationCost = await getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request: {\n from: request.from,\n sourceChainId: request.sourceChainId,\n sourceTokenAddress: request.sourceTokenAddress,\n },\n totalGasEstimate,\n totalItemCount,\n });\n\n if (!gasStationCost) {\n return undefined;\n }\n\n return {\n amount: new BigNumber(gasStationCost.raw),\n source: GasCostEstimateSource.GasStation,\n };\n}\n\nasync function getProbeGasCostInSourceTokenRaw(\n context: MaxAmountQuoteContext,\n): Promise<BigNumber | undefined> {\n const { fullRequest, getSingleQuote, messenger, request } = context;\n\n const sourceTokenInfo = getTokenInfo(\n messenger,\n request.sourceTokenAddress,\n request.sourceChainId,\n );\n\n if (!sourceTokenInfo) {\n return undefined;\n }\n\n const probeAmount = getProbeSourceAmountRaw(\n request.sourceTokenAmount,\n sourceTokenInfo.decimals,\n );\n\n if (!probeAmount || probeAmount === request.sourceTokenAmount) {\n return undefined;\n }\n\n log('Requesting probe quote for gas station estimation', {\n originalSourceAmount: request.sourceTokenAmount,\n probeAmount,\n });\n\n let probeQuote: TransactionPayQuote<RelayQuote> | undefined;\n\n try {\n probeQuote = await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: probeAmount,\n },\n fullRequest,\n );\n } catch (error) {\n log('Probe quote request failed', { error });\n return undefined;\n }\n\n if (!probeQuote) {\n return undefined;\n }\n\n const probeEstimate = await getGasCostFromQuoteOrGasStation(\n probeQuote,\n messenger,\n request,\n );\n\n return probeEstimate?.amount;\n}\n\nfunction getProbeSourceAmountRaw(\n sourceAmountRaw: string,\n sourceDecimals: number,\n): string | undefined {\n const sourceAmount = new BigNumber(sourceAmountRaw);\n\n if (sourceAmount.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n const probeRawAmount = sourceAmount\n .multipliedBy(PROBE_AMOUNT_PERCENTAGE)\n .integerValue(BigNumber.ROUND_FLOOR);\n\n // Minimum probe size: ~0.01 token for tokens with >=2 decimals,\n // otherwise one raw unit for low-decimal tokens.\n const minimumProbeRaw = new BigNumber(1).shiftedBy(\n Math.max(sourceDecimals - 2, 0),\n );\n\n const probeRaw = BigNumber.minimum(\n sourceAmount,\n BigNumber.maximum(probeRawAmount, minimumProbeRaw),\n ).integerValue(BigNumber.ROUND_FLOOR);\n\n if (probeRaw.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n return probeRaw.toFixed(0);\n}\n\nfunction fallbackToPhase1(\n phase1Quote: TransactionPayQuote<RelayQuote>,\n message: string,\n paramsToLog?: Record<string, unknown>,\n): TransactionPayQuote<RelayQuote> {\n log(message, paramsToLog);\n return phase1Quote;\n}\n\nfunction hasMatchingGasLimitShape(phase1: number[], phase2: number[]): boolean {\n return phase1.length === phase2.length;\n}\n\nfunction getTotalGasLimit(gasLimits: number[]): number {\n return gasLimits.reduce((total, gasLimit) => total + gasLimit, 0);\n}\n\nfunction markQuoteAsMaxGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n): void {\n quote.original.metamask = {\n ...quote.original.metamask,\n isMaxGasStation: true,\n };\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createModuleLogger } from "@metamask/utils";
|
|
2
2
|
import { BigNumber } from "bignumber.js";
|
|
3
3
|
import { projectLogger } from "../../logger.mjs";
|
|
4
|
+
import { getGasStationEligibility, getGasStationCostInSourceTokenRaw } from "../../utils/gas-station.mjs";
|
|
4
5
|
import { getNativeToken, getTokenBalance, getTokenInfo } from "../../utils/token.mjs";
|
|
5
|
-
import { getGasStationEligibility, getGasStationCostInSourceTokenRaw } from "./gas-station.mjs";
|
|
6
6
|
const log = createModuleLogger(projectLogger, 'relay-max-gas-station');
|
|
7
7
|
const PROBE_AMOUNT_PERCENTAGE = 0.25;
|
|
8
8
|
var GasCostEstimateSource;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-max-gas-station.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-max-gas-station.ts"],"names":[],"mappings":"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","sourcesContent":["import { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenInfo,\n} from '../../utils/token';\nimport {\n getGasStationEligibility,\n getGasStationCostInSourceTokenRaw,\n} from './gas-station';\nimport type { RelayQuote, RelayTransactionStep } from './types';\n\nconst log = createModuleLogger(projectLogger, 'relay-max-gas-station');\n\nconst PROBE_AMOUNT_PERCENTAGE = 0.25;\n\nenum GasCostEstimateSource {\n GasStation = 'gas-station',\n Probe = 'probe',\n Quote = 'quote',\n}\n\ntype GasCostEstimate = {\n amount: BigNumber;\n source: GasCostEstimateSource;\n};\n\ntype NativeBalanceCheckResult = {\n hasEnoughNativeBalance: boolean;\n nativeBalance?: string;\n nativeGasCostRaw?: string;\n};\n\ntype GetSingleQuoteFn = (\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n) => Promise<TransactionPayQuote<RelayQuote>>;\n\ntype MaxAmountQuoteContext = {\n fullRequest: PayStrategyGetQuotesRequest;\n getSingleQuote: GetSingleQuoteFn;\n messenger: TransactionPayControllerMessenger;\n request: QuoteRequest;\n};\n\n/**\n * Returns a Relay max-amount quote using a two-phase gas-station fallback.\n *\n * It first requests a standard max quote (phase 1), then when needed estimates\n * gas in source-token units (directly or via a probe quote), requests an\n * adjusted max quote (phase 2), and accepts phase 2 only if validation passes\n * (source gas fee token selected, gas-limit checks, affordability).\n *\n * If any step fails or validation is unsafe, it safely falls back to phase 1.\n * Successful phase-2 quotes are tagged with `metamask.isMaxGasStation = true`.\n *\n * @param request - Relay quote request for a max-amount flow.\n * @param fullRequest - Full quote request context including messenger and transaction.\n * @param getSingleQuote - Quote fetcher used for phase-1, phase-2, and probe quotes.\n * @returns The validated adjusted phase-2 quote, or the original phase-1 quote on fallback.\n */\nexport async function getRelayMaxGasStationQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n getSingleQuote: GetSingleQuoteFn,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n const { sourceChainId, sourceTokenAmount } = request;\n const context: MaxAmountQuoteContext = {\n fullRequest,\n getSingleQuote,\n messenger,\n request,\n };\n\n const phase1Quote = await getSingleQuote(request, fullRequest);\n\n const nativeBalanceCheck = checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n phase1Quote,\n messenger,\n request,\n );\n\n if (nativeBalanceCheck.hasEnoughNativeBalance) {\n return fallbackToPhase1(\n phase1Quote,\n 'Native balance is sufficient for gas',\n {\n nativeBalance: nativeBalanceCheck.nativeBalance,\n nativeGasCost: nativeBalanceCheck.nativeGasCostRaw,\n },\n );\n }\n\n const gasStationEligibility = getGasStationEligibility(\n messenger,\n sourceChainId,\n );\n\n if (!gasStationEligibility.isEligible) {\n return fallbackToPhase1(\n phase1Quote,\n 'Gas station is disabled or unsupported',\n );\n }\n\n const sourceAmountBN = new BigNumber(sourceTokenAmount);\n const probeCost = await getProbeGasCostInSourceTokenRaw(context);\n\n if (!probeCost) {\n return fallbackToPhase1(\n phase1Quote,\n 'Unable to estimate gas-station source token cost',\n );\n }\n\n const initialGasEstimate: GasCostEstimate = {\n amount: probeCost,\n source: GasCostEstimateSource.Probe,\n };\n\n const adjustedSourceAmount = getAdjustedSourceAmount(\n sourceAmountBN,\n initialGasEstimate.amount,\n );\n\n if (!adjustedSourceAmount.isGreaterThan(0)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Insufficient balance for gas station after max adjustment',\n );\n }\n\n const phase2Quote = await getAdjustedPhase2Quote(\n adjustedSourceAmount,\n initialGasEstimate,\n context,\n );\n\n if (!phase2Quote) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted phase-2 quote request failed',\n );\n }\n\n if (!phase2Quote.fees.isSourceGasFeeToken) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote did not return source gas fee token pricing',\n );\n }\n\n const phase1GasLimits = phase1Quote.original.metamask.gasLimits ?? [];\n const phase2GasLimits = phase2Quote.original.metamask.gasLimits ?? [];\n\n if (!hasMatchingGasLimitShape(phase1GasLimits, phase2GasLimits)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote gas limit shape changed between phases',\n {\n phase1GasLimits,\n phase2GasLimits,\n },\n );\n }\n\n const phase1TotalGasLimit = getTotalGasLimit(phase1GasLimits);\n const phase2TotalGasLimit = getTotalGasLimit(phase2GasLimits);\n\n if (phase2TotalGasLimit > phase1TotalGasLimit) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote total gas limit increased between phases',\n {\n phase1TotalGasLimit,\n phase2TotalGasLimit,\n },\n );\n }\n\n const validationGasEstimate = new BigNumber(\n phase2Quote.fees.sourceNetwork.max.raw,\n );\n\n if (\n !isAdjustedAmountAffordable(\n adjustedSourceAmount,\n validationGasEstimate,\n sourceAmountBN,\n )\n ) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote fails affordability validation',\n {\n adjustedSourceAmount: adjustedSourceAmount.toString(10),\n validationGasCost: validationGasEstimate.toString(10),\n },\n );\n }\n\n markQuoteAsMaxGasStation(phase2Quote);\n\n return phase2Quote;\n}\n\nfunction checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): NativeBalanceCheckResult {\n if (quote.fees.isSourceGasFeeToken) {\n return { hasEnoughNativeBalance: false };\n }\n\n const nativeGasCostRaw = quote.fees.sourceNetwork.max.raw;\n const nativeBalance = getTokenBalance(\n messenger,\n request.from,\n request.sourceChainId,\n getNativeToken(request.sourceChainId),\n );\n\n return {\n hasEnoughNativeBalance: new BigNumber(nativeBalance).isGreaterThanOrEqualTo(\n nativeGasCostRaw,\n ),\n nativeBalance,\n nativeGasCostRaw,\n };\n}\n\nfunction getAdjustedSourceAmount(\n sourceAmount: BigNumber,\n estimatedGasCost: BigNumber,\n): BigNumber {\n return sourceAmount\n .minus(estimatedGasCost)\n .integerValue(BigNumber.ROUND_DOWN);\n}\n\nfunction isAdjustedAmountAffordable(\n adjustedSourceAmount: BigNumber,\n gasCost: BigNumber,\n originalSourceAmount: BigNumber,\n): boolean {\n return adjustedSourceAmount\n .plus(gasCost)\n .isLessThanOrEqualTo(originalSourceAmount);\n}\n\nasync function getAdjustedPhase2Quote(\n adjustedSourceAmount: BigNumber,\n initialGasEstimate: GasCostEstimate,\n context: MaxAmountQuoteContext,\n): Promise<TransactionPayQuote<RelayQuote> | undefined> {\n const { fullRequest, getSingleQuote, request } = context;\n\n log('Requesting adjusted max quote', {\n adjustedAmount: adjustedSourceAmount.toString(10),\n gasCostInSourceToken: initialGasEstimate.amount.toString(10),\n gasEstimateSource: initialGasEstimate.source,\n originalAmount: request.sourceTokenAmount,\n });\n\n try {\n return await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: adjustedSourceAmount.toFixed(\n 0,\n BigNumber.ROUND_DOWN,\n ),\n },\n fullRequest,\n );\n } catch (error) {\n log('Adjusted quote request failed, falling back to phase-1 quote', {\n error,\n });\n return undefined;\n }\n}\n\nasync function getGasCostFromQuoteOrGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): Promise<GasCostEstimate | undefined> {\n const gasCost = quote.fees.sourceNetwork.max;\n\n if (quote.fees.isSourceGasFeeToken) {\n log('Gas cost already in source token units', { raw: gasCost.raw });\n return {\n amount: new BigNumber(gasCost.raw),\n source: GasCostEstimateSource.Quote,\n };\n }\n\n const firstTxStep = quote.original.steps.find(\n (step): step is RelayTransactionStep => step.kind === 'transaction',\n );\n const firstStepData = firstTxStep?.items[0]?.data;\n\n if (!firstStepData) {\n return undefined;\n }\n\n const totalItemCount = quote.original.steps.reduce(\n (count, step) => count + step.items.length,\n 0,\n );\n\n const totalGasEstimate = (quote.original.metamask.gasLimits ?? []).reduce(\n (acc, gasLimit) => acc + gasLimit,\n 0,\n );\n\n const gasStationCost = await getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request: {\n from: request.from,\n sourceChainId: request.sourceChainId,\n sourceTokenAddress: request.sourceTokenAddress,\n },\n totalGasEstimate,\n totalItemCount,\n });\n\n if (!gasStationCost) {\n return undefined;\n }\n\n return {\n amount: new BigNumber(gasStationCost.raw),\n source: GasCostEstimateSource.GasStation,\n };\n}\n\nasync function getProbeGasCostInSourceTokenRaw(\n context: MaxAmountQuoteContext,\n): Promise<BigNumber | undefined> {\n const { fullRequest, getSingleQuote, messenger, request } = context;\n\n const sourceTokenInfo = getTokenInfo(\n messenger,\n request.sourceTokenAddress,\n request.sourceChainId,\n );\n\n if (!sourceTokenInfo) {\n return undefined;\n }\n\n const probeAmount = getProbeSourceAmountRaw(\n request.sourceTokenAmount,\n sourceTokenInfo.decimals,\n );\n\n if (!probeAmount || probeAmount === request.sourceTokenAmount) {\n return undefined;\n }\n\n log('Requesting probe quote for gas station estimation', {\n originalSourceAmount: request.sourceTokenAmount,\n probeAmount,\n });\n\n let probeQuote: TransactionPayQuote<RelayQuote> | undefined;\n\n try {\n probeQuote = await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: probeAmount,\n },\n fullRequest,\n );\n } catch (error) {\n log('Probe quote request failed', { error });\n return undefined;\n }\n\n if (!probeQuote) {\n return undefined;\n }\n\n const probeEstimate = await getGasCostFromQuoteOrGasStation(\n probeQuote,\n messenger,\n request,\n );\n\n return probeEstimate?.amount;\n}\n\nfunction getProbeSourceAmountRaw(\n sourceAmountRaw: string,\n sourceDecimals: number,\n): string | undefined {\n const sourceAmount = new BigNumber(sourceAmountRaw);\n\n if (sourceAmount.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n const probeRawAmount = sourceAmount\n .multipliedBy(PROBE_AMOUNT_PERCENTAGE)\n .integerValue(BigNumber.ROUND_FLOOR);\n\n // Minimum probe size: ~0.01 token for tokens with >=2 decimals,\n // otherwise one raw unit for low-decimal tokens.\n const minimumProbeRaw = new BigNumber(1).shiftedBy(\n Math.max(sourceDecimals - 2, 0),\n );\n\n const probeRaw = BigNumber.minimum(\n sourceAmount,\n BigNumber.maximum(probeRawAmount, minimumProbeRaw),\n ).integerValue(BigNumber.ROUND_FLOOR);\n\n if (probeRaw.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n return probeRaw.toFixed(0);\n}\n\nfunction fallbackToPhase1(\n phase1Quote: TransactionPayQuote<RelayQuote>,\n message: string,\n paramsToLog?: Record<string, unknown>,\n): TransactionPayQuote<RelayQuote> {\n log(message, paramsToLog);\n return phase1Quote;\n}\n\nfunction hasMatchingGasLimitShape(phase1: number[], phase2: number[]): boolean {\n return phase1.length === phase2.length;\n}\n\nfunction getTotalGasLimit(gasLimits: number[]): number {\n return gasLimits.reduce((total, gasLimit) => total + gasLimit, 0);\n}\n\nfunction markQuoteAsMaxGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n): void {\n quote.original.metamask = {\n ...quote.original.metamask,\n isMaxGasStation: true,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"relay-max-gas-station.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-max-gas-station.ts"],"names":[],"mappings":"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","sourcesContent":["import { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport {\n getGasStationEligibility,\n getGasStationCostInSourceTokenRaw,\n} from '../../utils/gas-station';\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenInfo,\n} from '../../utils/token';\nimport type { RelayQuote, RelayTransactionStep } from './types';\n\nconst log = createModuleLogger(projectLogger, 'relay-max-gas-station');\n\nconst PROBE_AMOUNT_PERCENTAGE = 0.25;\n\nenum GasCostEstimateSource {\n GasStation = 'gas-station',\n Probe = 'probe',\n Quote = 'quote',\n}\n\ntype GasCostEstimate = {\n amount: BigNumber;\n source: GasCostEstimateSource;\n};\n\ntype NativeBalanceCheckResult = {\n hasEnoughNativeBalance: boolean;\n nativeBalance?: string;\n nativeGasCostRaw?: string;\n};\n\ntype GetSingleQuoteFn = (\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n) => Promise<TransactionPayQuote<RelayQuote>>;\n\ntype MaxAmountQuoteContext = {\n fullRequest: PayStrategyGetQuotesRequest;\n getSingleQuote: GetSingleQuoteFn;\n messenger: TransactionPayControllerMessenger;\n request: QuoteRequest;\n};\n\n/**\n * Returns a Relay max-amount quote using a two-phase gas-station fallback.\n *\n * It first requests a standard max quote (phase 1), then when needed estimates\n * gas in source-token units (directly or via a probe quote), requests an\n * adjusted max quote (phase 2), and accepts phase 2 only if validation passes\n * (source gas fee token selected, gas-limit checks, affordability).\n *\n * If any step fails or validation is unsafe, it safely falls back to phase 1.\n * Successful phase-2 quotes are tagged with `metamask.isMaxGasStation = true`.\n *\n * @param request - Relay quote request for a max-amount flow.\n * @param fullRequest - Full quote request context including messenger and transaction.\n * @param getSingleQuote - Quote fetcher used for phase-1, phase-2, and probe quotes.\n * @returns The validated adjusted phase-2 quote, or the original phase-1 quote on fallback.\n */\nexport async function getRelayMaxGasStationQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n getSingleQuote: GetSingleQuoteFn,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n const { sourceChainId, sourceTokenAmount } = request;\n const context: MaxAmountQuoteContext = {\n fullRequest,\n getSingleQuote,\n messenger,\n request,\n };\n\n const phase1Quote = await getSingleQuote(request, fullRequest);\n\n const nativeBalanceCheck = checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n phase1Quote,\n messenger,\n request,\n );\n\n if (nativeBalanceCheck.hasEnoughNativeBalance) {\n return fallbackToPhase1(\n phase1Quote,\n 'Native balance is sufficient for gas',\n {\n nativeBalance: nativeBalanceCheck.nativeBalance,\n nativeGasCost: nativeBalanceCheck.nativeGasCostRaw,\n },\n );\n }\n\n const gasStationEligibility = getGasStationEligibility(\n messenger,\n sourceChainId,\n );\n\n if (!gasStationEligibility.isEligible) {\n return fallbackToPhase1(\n phase1Quote,\n 'Gas station is disabled or unsupported',\n );\n }\n\n const sourceAmountBN = new BigNumber(sourceTokenAmount);\n const probeCost = await getProbeGasCostInSourceTokenRaw(context);\n\n if (!probeCost) {\n return fallbackToPhase1(\n phase1Quote,\n 'Unable to estimate gas-station source token cost',\n );\n }\n\n const initialGasEstimate: GasCostEstimate = {\n amount: probeCost,\n source: GasCostEstimateSource.Probe,\n };\n\n const adjustedSourceAmount = getAdjustedSourceAmount(\n sourceAmountBN,\n initialGasEstimate.amount,\n );\n\n if (!adjustedSourceAmount.isGreaterThan(0)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Insufficient balance for gas station after max adjustment',\n );\n }\n\n const phase2Quote = await getAdjustedPhase2Quote(\n adjustedSourceAmount,\n initialGasEstimate,\n context,\n );\n\n if (!phase2Quote) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted phase-2 quote request failed',\n );\n }\n\n if (!phase2Quote.fees.isSourceGasFeeToken) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote did not return source gas fee token pricing',\n );\n }\n\n const phase1GasLimits = phase1Quote.original.metamask.gasLimits ?? [];\n const phase2GasLimits = phase2Quote.original.metamask.gasLimits ?? [];\n\n if (!hasMatchingGasLimitShape(phase1GasLimits, phase2GasLimits)) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote gas limit shape changed between phases',\n {\n phase1GasLimits,\n phase2GasLimits,\n },\n );\n }\n\n const phase1TotalGasLimit = getTotalGasLimit(phase1GasLimits);\n const phase2TotalGasLimit = getTotalGasLimit(phase2GasLimits);\n\n if (phase2TotalGasLimit > phase1TotalGasLimit) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote total gas limit increased between phases',\n {\n phase1TotalGasLimit,\n phase2TotalGasLimit,\n },\n );\n }\n\n const validationGasEstimate = new BigNumber(\n phase2Quote.fees.sourceNetwork.max.raw,\n );\n\n if (\n !isAdjustedAmountAffordable(\n adjustedSourceAmount,\n validationGasEstimate,\n sourceAmountBN,\n )\n ) {\n return fallbackToPhase1(\n phase1Quote,\n 'Adjusted quote fails affordability validation',\n {\n adjustedSourceAmount: adjustedSourceAmount.toString(10),\n validationGasCost: validationGasEstimate.toString(10),\n },\n );\n }\n\n markQuoteAsMaxGasStation(phase2Quote);\n\n return phase2Quote;\n}\n\nfunction checkEnoughNativeBalanceIfSourceGasFeeTokenNotUsed(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): NativeBalanceCheckResult {\n if (quote.fees.isSourceGasFeeToken) {\n return { hasEnoughNativeBalance: false };\n }\n\n const nativeGasCostRaw = quote.fees.sourceNetwork.max.raw;\n const nativeBalance = getTokenBalance(\n messenger,\n request.from,\n request.sourceChainId,\n getNativeToken(request.sourceChainId),\n );\n\n return {\n hasEnoughNativeBalance: new BigNumber(nativeBalance).isGreaterThanOrEqualTo(\n nativeGasCostRaw,\n ),\n nativeBalance,\n nativeGasCostRaw,\n };\n}\n\nfunction getAdjustedSourceAmount(\n sourceAmount: BigNumber,\n estimatedGasCost: BigNumber,\n): BigNumber {\n return sourceAmount\n .minus(estimatedGasCost)\n .integerValue(BigNumber.ROUND_DOWN);\n}\n\nfunction isAdjustedAmountAffordable(\n adjustedSourceAmount: BigNumber,\n gasCost: BigNumber,\n originalSourceAmount: BigNumber,\n): boolean {\n return adjustedSourceAmount\n .plus(gasCost)\n .isLessThanOrEqualTo(originalSourceAmount);\n}\n\nasync function getAdjustedPhase2Quote(\n adjustedSourceAmount: BigNumber,\n initialGasEstimate: GasCostEstimate,\n context: MaxAmountQuoteContext,\n): Promise<TransactionPayQuote<RelayQuote> | undefined> {\n const { fullRequest, getSingleQuote, request } = context;\n\n log('Requesting adjusted max quote', {\n adjustedAmount: adjustedSourceAmount.toString(10),\n gasCostInSourceToken: initialGasEstimate.amount.toString(10),\n gasEstimateSource: initialGasEstimate.source,\n originalAmount: request.sourceTokenAmount,\n });\n\n try {\n return await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: adjustedSourceAmount.toFixed(\n 0,\n BigNumber.ROUND_DOWN,\n ),\n },\n fullRequest,\n );\n } catch (error) {\n log('Adjusted quote request failed, falling back to phase-1 quote', {\n error,\n });\n return undefined;\n }\n}\n\nasync function getGasCostFromQuoteOrGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): Promise<GasCostEstimate | undefined> {\n const gasCost = quote.fees.sourceNetwork.max;\n\n if (quote.fees.isSourceGasFeeToken) {\n log('Gas cost already in source token units', { raw: gasCost.raw });\n return {\n amount: new BigNumber(gasCost.raw),\n source: GasCostEstimateSource.Quote,\n };\n }\n\n const firstTxStep = quote.original.steps.find(\n (step): step is RelayTransactionStep => step.kind === 'transaction',\n );\n const firstStepData = firstTxStep?.items[0]?.data;\n\n if (!firstStepData) {\n return undefined;\n }\n\n const totalItemCount = quote.original.steps.reduce(\n (count, step) => count + step.items.length,\n 0,\n );\n\n const totalGasEstimate = (quote.original.metamask.gasLimits ?? []).reduce(\n (acc, gasLimit) => acc + gasLimit,\n 0,\n );\n\n const gasStationCost = await getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request: {\n from: request.from,\n sourceChainId: request.sourceChainId,\n sourceTokenAddress: request.sourceTokenAddress,\n },\n totalGasEstimate,\n totalItemCount,\n });\n\n if (!gasStationCost) {\n return undefined;\n }\n\n return {\n amount: new BigNumber(gasStationCost.raw),\n source: GasCostEstimateSource.GasStation,\n };\n}\n\nasync function getProbeGasCostInSourceTokenRaw(\n context: MaxAmountQuoteContext,\n): Promise<BigNumber | undefined> {\n const { fullRequest, getSingleQuote, messenger, request } = context;\n\n const sourceTokenInfo = getTokenInfo(\n messenger,\n request.sourceTokenAddress,\n request.sourceChainId,\n );\n\n if (!sourceTokenInfo) {\n return undefined;\n }\n\n const probeAmount = getProbeSourceAmountRaw(\n request.sourceTokenAmount,\n sourceTokenInfo.decimals,\n );\n\n if (!probeAmount || probeAmount === request.sourceTokenAmount) {\n return undefined;\n }\n\n log('Requesting probe quote for gas station estimation', {\n originalSourceAmount: request.sourceTokenAmount,\n probeAmount,\n });\n\n let probeQuote: TransactionPayQuote<RelayQuote> | undefined;\n\n try {\n probeQuote = await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: probeAmount,\n },\n fullRequest,\n );\n } catch (error) {\n log('Probe quote request failed', { error });\n return undefined;\n }\n\n if (!probeQuote) {\n return undefined;\n }\n\n const probeEstimate = await getGasCostFromQuoteOrGasStation(\n probeQuote,\n messenger,\n request,\n );\n\n return probeEstimate?.amount;\n}\n\nfunction getProbeSourceAmountRaw(\n sourceAmountRaw: string,\n sourceDecimals: number,\n): string | undefined {\n const sourceAmount = new BigNumber(sourceAmountRaw);\n\n if (sourceAmount.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n const probeRawAmount = sourceAmount\n .multipliedBy(PROBE_AMOUNT_PERCENTAGE)\n .integerValue(BigNumber.ROUND_FLOOR);\n\n // Minimum probe size: ~0.01 token for tokens with >=2 decimals,\n // otherwise one raw unit for low-decimal tokens.\n const minimumProbeRaw = new BigNumber(1).shiftedBy(\n Math.max(sourceDecimals - 2, 0),\n );\n\n const probeRaw = BigNumber.minimum(\n sourceAmount,\n BigNumber.maximum(probeRawAmount, minimumProbeRaw),\n ).integerValue(BigNumber.ROUND_FLOOR);\n\n if (probeRaw.isLessThanOrEqualTo(0)) {\n return undefined;\n }\n\n return probeRaw.toFixed(0);\n}\n\nfunction fallbackToPhase1(\n phase1Quote: TransactionPayQuote<RelayQuote>,\n message: string,\n paramsToLog?: Record<string, unknown>,\n): TransactionPayQuote<RelayQuote> {\n log(message, paramsToLog);\n return phase1Quote;\n}\n\nfunction hasMatchingGasLimitShape(phase1: number[], phase2: number[]): boolean {\n return phase1.length === phase2.length;\n}\n\nfunction getTotalGasLimit(gasLimits: number[]): number {\n return gasLimits.reduce((total, gasLimit) => total + gasLimit, 0);\n}\n\nfunction markQuoteAsMaxGasStation(\n quote: TransactionPayQuote<RelayQuote>,\n): void {\n quote.original.metamask = {\n ...quote.original.metamask,\n isMaxGasStation: true,\n };\n}\n"]}
|
|
@@ -12,11 +12,11 @@ const logger_1 = require("../../logger.cjs");
|
|
|
12
12
|
const amounts_1 = require("../../utils/amounts.cjs");
|
|
13
13
|
const feature_flags_1 = require("../../utils/feature-flags.cjs");
|
|
14
14
|
const gas_1 = require("../../utils/gas.cjs");
|
|
15
|
+
const gas_station_1 = require("../../utils/gas-station.cjs");
|
|
15
16
|
const quote_gas_1 = require("../../utils/quote-gas.cjs");
|
|
16
17
|
const token_1 = require("../../utils/token.cjs");
|
|
17
18
|
const transaction_1 = require("../../utils/transaction.cjs");
|
|
18
19
|
const constants_2 = require("./constants.cjs");
|
|
19
|
-
const gas_station_1 = require("./gas-station.cjs");
|
|
20
20
|
const relay_api_1 = require("./relay-api.cjs");
|
|
21
21
|
const relay_max_gas_station_1 = require("./relay-max-gas-station.cjs");
|
|
22
22
|
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'relay-strategy');
|
|
@@ -31,10 +31,13 @@ async function getRelayQuotes(request) {
|
|
|
31
31
|
log('Fetching quotes', requests);
|
|
32
32
|
try {
|
|
33
33
|
const normalizedRequests = requests
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
singleRequest.
|
|
34
|
+
.filter((singleRequest) => {
|
|
35
|
+
const hasTargetMinimum = singleRequest.targetAmountMinimum !== '0';
|
|
36
|
+
const isPostQuote = Boolean(singleRequest.isPostQuote);
|
|
37
|
+
const isExactInputRequest = Boolean(singleRequest.isMaxAmount) &&
|
|
38
|
+
new bignumber_js_1.BigNumber(singleRequest.sourceTokenAmount).gt(0);
|
|
39
|
+
return hasTargetMinimum || isPostQuote || isExactInputRequest;
|
|
40
|
+
})
|
|
38
41
|
.map((singleRequest) => normalizeRequest(singleRequest));
|
|
39
42
|
log('Normalized requests', normalizedRequests);
|
|
40
43
|
return await Promise.all(normalizedRequests.map((singleRequest) => getQuoteWithMaxAmountHandling(singleRequest, request)));
|