@metamask/transaction-pay-controller 12.0.2 → 12.2.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 CHANGED
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [12.2.0]
11
+
12
+ ### Added
13
+
14
+ - Generate required tokens using `requiredAssets` from transaction metadata ([#7820](https://github.com/MetaMask/core/pull/7820))
15
+
16
+ ### Changed
17
+
18
+ - Bump `@metamask/bridge-controller` from `^65.2.0` to `^65.3.0` ([#7837](https://github.com/MetaMask/core/pull/7837))
19
+ - Bump `@metamask/bridge-status-controller` from `^65.0.1` to `^66.0.0` ([#7850](https://github.com/MetaMask/core/pull/7850))
20
+
21
+ ## [12.1.0]
22
+
23
+ ### Changed
24
+
25
+ - Bump `@metamask/transaction-controller` from `^62.11.0` to `^62.14.0` ([#7775](https://github.com/MetaMask/core/pull/7775), [#7802](https://github.com/MetaMask/core/pull/7802), [#7832](https://github.com/MetaMask/core/pull/7832))
26
+ - Bump `@metamask/assets-controllers` from `^99.1.0` to `^99.2.0` ([#7802](https://github.com/MetaMask/core/pull/7802))
27
+ - Bump `@metamask/bridge-controller` from `^65.1.0` to `^65.2.0` ([#7802](https://github.com/MetaMask/core/pull/7802))
28
+ - Poll Relay status for same-chain quotes with a single deposit step ([#7761](https://github.com/MetaMask/core/pull/7761))
29
+
10
30
  ## [12.0.2]
11
31
 
12
32
  ### Changed
@@ -320,7 +340,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
320
340
 
321
341
  - Initial release ([#6820](https://github.com/MetaMask/core/pull/6820))
322
342
 
323
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@12.0.2...HEAD
343
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@12.2.0...HEAD
344
+ [12.2.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@12.1.0...@metamask/transaction-pay-controller@12.2.0
345
+ [12.1.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@12.0.2...@metamask/transaction-pay-controller@12.1.0
324
346
  [12.0.2]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@12.0.1...@metamask/transaction-pay-controller@12.0.2
325
347
  [12.0.1]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@12.0.0...@metamask/transaction-pay-controller@12.0.1
326
348
  [12.0.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@11.1.1...@metamask/transaction-pay-controller@12.0.0
@@ -62,8 +62,10 @@ async function executeSingleQuote(quote, messenger, transaction) {
62
62
  * @returns A promise that resolves when the Relay request is complete.
63
63
  */
64
64
  async function waitForRelayCompletion(quote) {
65
- if (quote.details.currencyIn.currency.chainId ===
66
- quote.details.currencyOut.currency.chainId) {
65
+ const isSameChain = quote.details.currencyIn.currency.chainId ===
66
+ quote.details.currencyOut.currency.chainId;
67
+ const isSingleDepositStep = quote.steps.length === 1 && quote.steps[0].id === 'deposit';
68
+ if (isSameChain && !isSingleDepositStep) {
67
69
  log('Skipping polling as same chain');
68
70
  return FALLBACK_HASH;
69
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"relay-submit.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ORIGIN_METAMASK,\n successfulFetch,\n toHex,\n} from '@metamask/controller-utils';\nimport { TransactionType } from '@metamask/transaction-controller';\nimport type { TransactionParams } from '@metamask/transaction-controller';\nimport type {\n AuthorizationList,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { RELAY_POLLING_INTERVAL, RELAY_STATUS_URL } from './constants';\nimport type { RelayQuote, RelayStatusResponse } from './types';\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyExecuteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { getFeatureFlags } from '../../utils/feature-flags';\nimport {\n collectTransactionIds,\n getTransaction,\n updateTransaction,\n waitForTransactionConfirmed,\n} from '../../utils/transaction';\n\nconst FALLBACK_HASH = '0x0' as Hex;\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Submits Relay quotes.\n *\n * @param request - Request object.\n * @returns An object containing the transaction hash if available.\n */\nexport async function submitRelayQuotes(\n request: PayStrategyExecuteRequest<RelayQuote>,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing quotes', request);\n\n const { quotes, messenger, transaction } = request;\n\n let transactionHash: Hex | undefined;\n\n for (const quote of quotes) {\n ({ transactionHash } = await executeSingleQuote(\n quote,\n messenger,\n transaction,\n ));\n }\n\n return { transactionHash };\n}\n\n/**\n * Executes a single Relay quote.\n *\n * @param quote - Relay quote to execute.\n * @param messenger - Controller messenger.\n * @param transaction - Original transaction meta.\n * @returns An object containing the transaction hash if available.\n */\nasync function executeSingleQuote(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n transaction: TransactionMeta,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing single quote', quote);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Remove nonce from skipped transaction',\n },\n (tx) => {\n tx.txParams.nonce = undefined;\n },\n );\n\n await submitTransactions(quote, transaction.id, messenger);\n\n const targetHash = await waitForRelayCompletion(quote.original);\n\n log('Relay request completed', targetHash);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Intent complete after Relay completion',\n },\n (tx) => {\n tx.isIntentComplete = true;\n },\n );\n\n return { transactionHash: targetHash };\n}\n\n/**\n * Wait for a Relay request to complete.\n *\n * @param quote - Relay quote associated with the request.\n * @returns A promise that resolves when the Relay request is complete.\n */\nasync function waitForRelayCompletion(quote: RelayQuote): Promise<Hex> {\n if (\n quote.details.currencyIn.currency.chainId ===\n quote.details.currencyOut.currency.chainId\n ) {\n log('Skipping polling as same chain');\n return FALLBACK_HASH;\n }\n\n const { requestId } = quote.steps[0];\n const url = `${RELAY_STATUS_URL}?requestId=${requestId}`;\n\n while (true) {\n const response = await successfulFetch(url, { method: 'GET' });\n const status = (await response.json()) as RelayStatusResponse;\n\n log('Polled status', status.status, status);\n\n if (status.status === 'success') {\n const targetHash = status.txHashes?.slice(-1)[0] as Hex;\n return targetHash ?? FALLBACK_HASH;\n }\n\n if (['failure', 'refund', 'refunded'].includes(status.status)) {\n throw new Error(`Relay request failed with status: ${status.status}`);\n }\n\n await new Promise((resolve) => setTimeout(resolve, RELAY_POLLING_INTERVAL));\n }\n}\n\n/**\n * Normalize the parameters from a relay quote step to match TransactionParams.\n *\n * @param params - Parameters from a relay quote step.\n * @param messenger - Controller messenger.\n * @returns Normalized transaction parameters.\n */\nfunction normalizeParams(\n params: RelayQuote['steps'][0]['items'][0]['data'],\n messenger: TransactionPayControllerMessenger,\n): TransactionParams {\n const featureFlags = getFeatureFlags(messenger);\n\n return {\n data: params.data,\n from: params.from,\n gas: toHex(params.gas ?? featureFlags.relayFallbackGas.max),\n maxFeePerGas: toHex(params.maxFeePerGas),\n maxPriorityFeePerGas: toHex(params.maxPriorityFeePerGas),\n to: params.to,\n value: toHex(params.value ?? '0'),\n };\n}\n\n/**\n * Submit transactions for a relay quote.\n *\n * @param quote - Relay quote.\n * @param parentTransactionId - ID of the parent transaction.\n * @param messenger - Controller messenger.\n * @returns Hash of the last submitted transaction.\n */\nasync function submitTransactions(\n quote: TransactionPayQuote<RelayQuote>,\n parentTransactionId: string,\n messenger: TransactionPayControllerMessenger,\n): Promise<Hex> {\n const { steps } = quote.original;\n const params = steps.flatMap((step) => step.items).map((item) => item.data);\n const invalidKind = steps.find((step) => step.kind !== 'transaction')?.kind;\n\n if (invalidKind) {\n throw new Error(`Unsupported step kind: ${invalidKind}`);\n }\n\n const normalizedParams = params.map((singleParams) =>\n normalizeParams(singleParams, messenger),\n );\n\n const transactionIds: string[] = [];\n const { from, sourceChainId, sourceTokenAddress } = quote.request;\n\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n sourceChainId,\n );\n\n log('Adding transactions', {\n normalizedParams,\n sourceChainId,\n from,\n networkClientId,\n });\n\n const { end } = collectTransactionIds(\n sourceChainId,\n from,\n messenger,\n (transactionId) => {\n transactionIds.push(transactionId);\n\n updateTransaction(\n {\n transactionId: parentTransactionId,\n messenger,\n note: 'Add required transaction ID from Relay submission',\n },\n (tx) => {\n tx.requiredTransactionIds ??= [];\n tx.requiredTransactionIds.push(transactionId);\n },\n );\n },\n );\n\n let result: { result: Promise<string> } | undefined;\n\n const gasFeeToken = quote.fees.isSourceGasFeeToken\n ? sourceTokenAddress\n : undefined;\n\n const isSameChain =\n quote.original.details.currencyIn.currency.chainId ===\n quote.original.details.currencyOut.currency.chainId;\n\n const authorizationList: AuthorizationList | undefined =\n isSameChain && quote.original.request.authorizationList?.length\n ? quote.original.request.authorizationList.map((a) => ({\n address: a.address,\n chainId: toHex(a.chainId),\n }))\n : undefined;\n\n const { gasLimits } = quote.original.metamask;\n\n if (params.length === 1) {\n const transactionParams = {\n ...normalizedParams[0],\n authorizationList,\n gas: toHex(gasLimits[0]),\n };\n\n result = await messenger.call(\n 'TransactionController:addTransaction',\n transactionParams,\n {\n gasFeeToken,\n networkClientId,\n origin: ORIGIN_METAMASK,\n requireApproval: false,\n type: TransactionType.relayDeposit,\n },\n );\n } else {\n const gasLimit7702 =\n gasLimits.length === 1 ? toHex(gasLimits[0]) : undefined;\n\n const transactions = normalizedParams.map((singleParams, index) => ({\n params: {\n data: singleParams.data as Hex,\n gas: gasLimit7702 ? undefined : toHex(gasLimits[index]),\n maxFeePerGas: singleParams.maxFeePerGas as Hex,\n maxPriorityFeePerGas: singleParams.maxPriorityFeePerGas as Hex,\n to: singleParams.to as Hex,\n value: singleParams.value as Hex,\n },\n type:\n index === 0\n ? TransactionType.tokenMethodApprove\n : TransactionType.relayDeposit,\n }));\n\n await messenger.call('TransactionController:addTransactionBatch', {\n from,\n disable7702: !gasLimit7702,\n disableHook: Boolean(gasLimit7702),\n disableSequential: Boolean(gasLimit7702),\n gasFeeToken,\n gasLimit7702,\n networkClientId,\n origin: ORIGIN_METAMASK,\n overwriteUpgrade: true,\n requireApproval: false,\n transactions,\n });\n }\n\n end();\n\n log('Added transactions', transactionIds);\n\n if (result) {\n const txHash = await result.result;\n log('Submitted transaction', txHash);\n }\n\n await Promise.all(\n transactionIds.map((txId) => waitForTransactionConfirmed(txId, messenger)),\n );\n\n log('All transactions confirmed', transactionIds);\n\n const hash = getTransaction(transactionIds.slice(-1)[0], messenger)?.hash;\n\n return hash as Hex;\n}\n"]}
1
+ {"version":3,"file":"relay-submit.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ORIGIN_METAMASK,\n successfulFetch,\n toHex,\n} from '@metamask/controller-utils';\nimport { TransactionType } from '@metamask/transaction-controller';\nimport type { TransactionParams } from '@metamask/transaction-controller';\nimport type {\n AuthorizationList,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { RELAY_POLLING_INTERVAL, RELAY_STATUS_URL } from './constants';\nimport type { RelayQuote, RelayStatusResponse } from './types';\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyExecuteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { getFeatureFlags } from '../../utils/feature-flags';\nimport {\n collectTransactionIds,\n getTransaction,\n updateTransaction,\n waitForTransactionConfirmed,\n} from '../../utils/transaction';\n\nconst FALLBACK_HASH = '0x0' as Hex;\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Submits Relay quotes.\n *\n * @param request - Request object.\n * @returns An object containing the transaction hash if available.\n */\nexport async function submitRelayQuotes(\n request: PayStrategyExecuteRequest<RelayQuote>,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing quotes', request);\n\n const { quotes, messenger, transaction } = request;\n\n let transactionHash: Hex | undefined;\n\n for (const quote of quotes) {\n ({ transactionHash } = await executeSingleQuote(\n quote,\n messenger,\n transaction,\n ));\n }\n\n return { transactionHash };\n}\n\n/**\n * Executes a single Relay quote.\n *\n * @param quote - Relay quote to execute.\n * @param messenger - Controller messenger.\n * @param transaction - Original transaction meta.\n * @returns An object containing the transaction hash if available.\n */\nasync function executeSingleQuote(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n transaction: TransactionMeta,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing single quote', quote);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Remove nonce from skipped transaction',\n },\n (tx) => {\n tx.txParams.nonce = undefined;\n },\n );\n\n await submitTransactions(quote, transaction.id, messenger);\n\n const targetHash = await waitForRelayCompletion(quote.original);\n\n log('Relay request completed', targetHash);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Intent complete after Relay completion',\n },\n (tx) => {\n tx.isIntentComplete = true;\n },\n );\n\n return { transactionHash: targetHash };\n}\n\n/**\n * Wait for a Relay request to complete.\n *\n * @param quote - Relay quote associated with the request.\n * @returns A promise that resolves when the Relay request is complete.\n */\nasync function waitForRelayCompletion(quote: RelayQuote): Promise<Hex> {\n const isSameChain =\n quote.details.currencyIn.currency.chainId ===\n quote.details.currencyOut.currency.chainId;\n\n const isSingleDepositStep =\n quote.steps.length === 1 && quote.steps[0].id === 'deposit';\n\n if (isSameChain && !isSingleDepositStep) {\n log('Skipping polling as same chain');\n return FALLBACK_HASH;\n }\n\n const { requestId } = quote.steps[0];\n const url = `${RELAY_STATUS_URL}?requestId=${requestId}`;\n\n while (true) {\n const response = await successfulFetch(url, { method: 'GET' });\n const status = (await response.json()) as RelayStatusResponse;\n\n log('Polled status', status.status, status);\n\n if (status.status === 'success') {\n const targetHash = status.txHashes?.slice(-1)[0] as Hex;\n return targetHash ?? FALLBACK_HASH;\n }\n\n if (['failure', 'refund', 'refunded'].includes(status.status)) {\n throw new Error(`Relay request failed with status: ${status.status}`);\n }\n\n await new Promise((resolve) => setTimeout(resolve, RELAY_POLLING_INTERVAL));\n }\n}\n\n/**\n * Normalize the parameters from a relay quote step to match TransactionParams.\n *\n * @param params - Parameters from a relay quote step.\n * @param messenger - Controller messenger.\n * @returns Normalized transaction parameters.\n */\nfunction normalizeParams(\n params: RelayQuote['steps'][0]['items'][0]['data'],\n messenger: TransactionPayControllerMessenger,\n): TransactionParams {\n const featureFlags = getFeatureFlags(messenger);\n\n return {\n data: params.data,\n from: params.from,\n gas: toHex(params.gas ?? featureFlags.relayFallbackGas.max),\n maxFeePerGas: toHex(params.maxFeePerGas),\n maxPriorityFeePerGas: toHex(params.maxPriorityFeePerGas),\n to: params.to,\n value: toHex(params.value ?? '0'),\n };\n}\n\n/**\n * Submit transactions for a relay quote.\n *\n * @param quote - Relay quote.\n * @param parentTransactionId - ID of the parent transaction.\n * @param messenger - Controller messenger.\n * @returns Hash of the last submitted transaction.\n */\nasync function submitTransactions(\n quote: TransactionPayQuote<RelayQuote>,\n parentTransactionId: string,\n messenger: TransactionPayControllerMessenger,\n): Promise<Hex> {\n const { steps } = quote.original;\n const params = steps.flatMap((step) => step.items).map((item) => item.data);\n const invalidKind = steps.find((step) => step.kind !== 'transaction')?.kind;\n\n if (invalidKind) {\n throw new Error(`Unsupported step kind: ${invalidKind}`);\n }\n\n const normalizedParams = params.map((singleParams) =>\n normalizeParams(singleParams, messenger),\n );\n\n const transactionIds: string[] = [];\n const { from, sourceChainId, sourceTokenAddress } = quote.request;\n\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n sourceChainId,\n );\n\n log('Adding transactions', {\n normalizedParams,\n sourceChainId,\n from,\n networkClientId,\n });\n\n const { end } = collectTransactionIds(\n sourceChainId,\n from,\n messenger,\n (transactionId) => {\n transactionIds.push(transactionId);\n\n updateTransaction(\n {\n transactionId: parentTransactionId,\n messenger,\n note: 'Add required transaction ID from Relay submission',\n },\n (tx) => {\n tx.requiredTransactionIds ??= [];\n tx.requiredTransactionIds.push(transactionId);\n },\n );\n },\n );\n\n let result: { result: Promise<string> } | undefined;\n\n const gasFeeToken = quote.fees.isSourceGasFeeToken\n ? sourceTokenAddress\n : undefined;\n\n const isSameChain =\n quote.original.details.currencyIn.currency.chainId ===\n quote.original.details.currencyOut.currency.chainId;\n\n const authorizationList: AuthorizationList | undefined =\n isSameChain && quote.original.request.authorizationList?.length\n ? quote.original.request.authorizationList.map((a) => ({\n address: a.address,\n chainId: toHex(a.chainId),\n }))\n : undefined;\n\n const { gasLimits } = quote.original.metamask;\n\n if (params.length === 1) {\n const transactionParams = {\n ...normalizedParams[0],\n authorizationList,\n gas: toHex(gasLimits[0]),\n };\n\n result = await messenger.call(\n 'TransactionController:addTransaction',\n transactionParams,\n {\n gasFeeToken,\n networkClientId,\n origin: ORIGIN_METAMASK,\n requireApproval: false,\n type: TransactionType.relayDeposit,\n },\n );\n } else {\n const gasLimit7702 =\n gasLimits.length === 1 ? toHex(gasLimits[0]) : undefined;\n\n const transactions = normalizedParams.map((singleParams, index) => ({\n params: {\n data: singleParams.data as Hex,\n gas: gasLimit7702 ? undefined : toHex(gasLimits[index]),\n maxFeePerGas: singleParams.maxFeePerGas as Hex,\n maxPriorityFeePerGas: singleParams.maxPriorityFeePerGas as Hex,\n to: singleParams.to as Hex,\n value: singleParams.value as Hex,\n },\n type:\n index === 0\n ? TransactionType.tokenMethodApprove\n : TransactionType.relayDeposit,\n }));\n\n await messenger.call('TransactionController:addTransactionBatch', {\n from,\n disable7702: !gasLimit7702,\n disableHook: Boolean(gasLimit7702),\n disableSequential: Boolean(gasLimit7702),\n gasFeeToken,\n gasLimit7702,\n networkClientId,\n origin: ORIGIN_METAMASK,\n overwriteUpgrade: true,\n requireApproval: false,\n transactions,\n });\n }\n\n end();\n\n log('Added transactions', transactionIds);\n\n if (result) {\n const txHash = await result.result;\n log('Submitted transaction', txHash);\n }\n\n await Promise.all(\n transactionIds.map((txId) => waitForTransactionConfirmed(txId, messenger)),\n );\n\n log('All transactions confirmed', transactionIds);\n\n const hash = getTransaction(transactionIds.slice(-1)[0], messenger)?.hash;\n\n return hash as Hex;\n}\n"]}
@@ -58,8 +58,10 @@ async function executeSingleQuote(quote, messenger, transaction) {
58
58
  * @returns A promise that resolves when the Relay request is complete.
59
59
  */
60
60
  async function waitForRelayCompletion(quote) {
61
- if (quote.details.currencyIn.currency.chainId ===
62
- quote.details.currencyOut.currency.chainId) {
61
+ const isSameChain = quote.details.currencyIn.currency.chainId ===
62
+ quote.details.currencyOut.currency.chainId;
63
+ const isSingleDepositStep = quote.steps.length === 1 && quote.steps[0].id === 'deposit';
64
+ if (isSameChain && !isSingleDepositStep) {
63
65
  log('Skipping polling as same chain');
64
66
  return FALLBACK_HASH;
65
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"relay-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ORIGIN_METAMASK,\n successfulFetch,\n toHex,\n} from '@metamask/controller-utils';\nimport { TransactionType } from '@metamask/transaction-controller';\nimport type { TransactionParams } from '@metamask/transaction-controller';\nimport type {\n AuthorizationList,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { RELAY_POLLING_INTERVAL, RELAY_STATUS_URL } from './constants';\nimport type { RelayQuote, RelayStatusResponse } from './types';\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyExecuteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { getFeatureFlags } from '../../utils/feature-flags';\nimport {\n collectTransactionIds,\n getTransaction,\n updateTransaction,\n waitForTransactionConfirmed,\n} from '../../utils/transaction';\n\nconst FALLBACK_HASH = '0x0' as Hex;\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Submits Relay quotes.\n *\n * @param request - Request object.\n * @returns An object containing the transaction hash if available.\n */\nexport async function submitRelayQuotes(\n request: PayStrategyExecuteRequest<RelayQuote>,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing quotes', request);\n\n const { quotes, messenger, transaction } = request;\n\n let transactionHash: Hex | undefined;\n\n for (const quote of quotes) {\n ({ transactionHash } = await executeSingleQuote(\n quote,\n messenger,\n transaction,\n ));\n }\n\n return { transactionHash };\n}\n\n/**\n * Executes a single Relay quote.\n *\n * @param quote - Relay quote to execute.\n * @param messenger - Controller messenger.\n * @param transaction - Original transaction meta.\n * @returns An object containing the transaction hash if available.\n */\nasync function executeSingleQuote(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n transaction: TransactionMeta,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing single quote', quote);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Remove nonce from skipped transaction',\n },\n (tx) => {\n tx.txParams.nonce = undefined;\n },\n );\n\n await submitTransactions(quote, transaction.id, messenger);\n\n const targetHash = await waitForRelayCompletion(quote.original);\n\n log('Relay request completed', targetHash);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Intent complete after Relay completion',\n },\n (tx) => {\n tx.isIntentComplete = true;\n },\n );\n\n return { transactionHash: targetHash };\n}\n\n/**\n * Wait for a Relay request to complete.\n *\n * @param quote - Relay quote associated with the request.\n * @returns A promise that resolves when the Relay request is complete.\n */\nasync function waitForRelayCompletion(quote: RelayQuote): Promise<Hex> {\n if (\n quote.details.currencyIn.currency.chainId ===\n quote.details.currencyOut.currency.chainId\n ) {\n log('Skipping polling as same chain');\n return FALLBACK_HASH;\n }\n\n const { requestId } = quote.steps[0];\n const url = `${RELAY_STATUS_URL}?requestId=${requestId}`;\n\n while (true) {\n const response = await successfulFetch(url, { method: 'GET' });\n const status = (await response.json()) as RelayStatusResponse;\n\n log('Polled status', status.status, status);\n\n if (status.status === 'success') {\n const targetHash = status.txHashes?.slice(-1)[0] as Hex;\n return targetHash ?? FALLBACK_HASH;\n }\n\n if (['failure', 'refund', 'refunded'].includes(status.status)) {\n throw new Error(`Relay request failed with status: ${status.status}`);\n }\n\n await new Promise((resolve) => setTimeout(resolve, RELAY_POLLING_INTERVAL));\n }\n}\n\n/**\n * Normalize the parameters from a relay quote step to match TransactionParams.\n *\n * @param params - Parameters from a relay quote step.\n * @param messenger - Controller messenger.\n * @returns Normalized transaction parameters.\n */\nfunction normalizeParams(\n params: RelayQuote['steps'][0]['items'][0]['data'],\n messenger: TransactionPayControllerMessenger,\n): TransactionParams {\n const featureFlags = getFeatureFlags(messenger);\n\n return {\n data: params.data,\n from: params.from,\n gas: toHex(params.gas ?? featureFlags.relayFallbackGas.max),\n maxFeePerGas: toHex(params.maxFeePerGas),\n maxPriorityFeePerGas: toHex(params.maxPriorityFeePerGas),\n to: params.to,\n value: toHex(params.value ?? '0'),\n };\n}\n\n/**\n * Submit transactions for a relay quote.\n *\n * @param quote - Relay quote.\n * @param parentTransactionId - ID of the parent transaction.\n * @param messenger - Controller messenger.\n * @returns Hash of the last submitted transaction.\n */\nasync function submitTransactions(\n quote: TransactionPayQuote<RelayQuote>,\n parentTransactionId: string,\n messenger: TransactionPayControllerMessenger,\n): Promise<Hex> {\n const { steps } = quote.original;\n const params = steps.flatMap((step) => step.items).map((item) => item.data);\n const invalidKind = steps.find((step) => step.kind !== 'transaction')?.kind;\n\n if (invalidKind) {\n throw new Error(`Unsupported step kind: ${invalidKind}`);\n }\n\n const normalizedParams = params.map((singleParams) =>\n normalizeParams(singleParams, messenger),\n );\n\n const transactionIds: string[] = [];\n const { from, sourceChainId, sourceTokenAddress } = quote.request;\n\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n sourceChainId,\n );\n\n log('Adding transactions', {\n normalizedParams,\n sourceChainId,\n from,\n networkClientId,\n });\n\n const { end } = collectTransactionIds(\n sourceChainId,\n from,\n messenger,\n (transactionId) => {\n transactionIds.push(transactionId);\n\n updateTransaction(\n {\n transactionId: parentTransactionId,\n messenger,\n note: 'Add required transaction ID from Relay submission',\n },\n (tx) => {\n tx.requiredTransactionIds ??= [];\n tx.requiredTransactionIds.push(transactionId);\n },\n );\n },\n );\n\n let result: { result: Promise<string> } | undefined;\n\n const gasFeeToken = quote.fees.isSourceGasFeeToken\n ? sourceTokenAddress\n : undefined;\n\n const isSameChain =\n quote.original.details.currencyIn.currency.chainId ===\n quote.original.details.currencyOut.currency.chainId;\n\n const authorizationList: AuthorizationList | undefined =\n isSameChain && quote.original.request.authorizationList?.length\n ? quote.original.request.authorizationList.map((a) => ({\n address: a.address,\n chainId: toHex(a.chainId),\n }))\n : undefined;\n\n const { gasLimits } = quote.original.metamask;\n\n if (params.length === 1) {\n const transactionParams = {\n ...normalizedParams[0],\n authorizationList,\n gas: toHex(gasLimits[0]),\n };\n\n result = await messenger.call(\n 'TransactionController:addTransaction',\n transactionParams,\n {\n gasFeeToken,\n networkClientId,\n origin: ORIGIN_METAMASK,\n requireApproval: false,\n type: TransactionType.relayDeposit,\n },\n );\n } else {\n const gasLimit7702 =\n gasLimits.length === 1 ? toHex(gasLimits[0]) : undefined;\n\n const transactions = normalizedParams.map((singleParams, index) => ({\n params: {\n data: singleParams.data as Hex,\n gas: gasLimit7702 ? undefined : toHex(gasLimits[index]),\n maxFeePerGas: singleParams.maxFeePerGas as Hex,\n maxPriorityFeePerGas: singleParams.maxPriorityFeePerGas as Hex,\n to: singleParams.to as Hex,\n value: singleParams.value as Hex,\n },\n type:\n index === 0\n ? TransactionType.tokenMethodApprove\n : TransactionType.relayDeposit,\n }));\n\n await messenger.call('TransactionController:addTransactionBatch', {\n from,\n disable7702: !gasLimit7702,\n disableHook: Boolean(gasLimit7702),\n disableSequential: Boolean(gasLimit7702),\n gasFeeToken,\n gasLimit7702,\n networkClientId,\n origin: ORIGIN_METAMASK,\n overwriteUpgrade: true,\n requireApproval: false,\n transactions,\n });\n }\n\n end();\n\n log('Added transactions', transactionIds);\n\n if (result) {\n const txHash = await result.result;\n log('Submitted transaction', txHash);\n }\n\n await Promise.all(\n transactionIds.map((txId) => waitForTransactionConfirmed(txId, messenger)),\n );\n\n log('All transactions confirmed', transactionIds);\n\n const hash = getTransaction(transactionIds.slice(-1)[0], messenger)?.hash;\n\n return hash as Hex;\n}\n"]}
1
+ {"version":3,"file":"relay-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ORIGIN_METAMASK,\n successfulFetch,\n toHex,\n} from '@metamask/controller-utils';\nimport { TransactionType } from '@metamask/transaction-controller';\nimport type { TransactionParams } from '@metamask/transaction-controller';\nimport type {\n AuthorizationList,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { RELAY_POLLING_INTERVAL, RELAY_STATUS_URL } from './constants';\nimport type { RelayQuote, RelayStatusResponse } from './types';\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyExecuteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { getFeatureFlags } from '../../utils/feature-flags';\nimport {\n collectTransactionIds,\n getTransaction,\n updateTransaction,\n waitForTransactionConfirmed,\n} from '../../utils/transaction';\n\nconst FALLBACK_HASH = '0x0' as Hex;\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Submits Relay quotes.\n *\n * @param request - Request object.\n * @returns An object containing the transaction hash if available.\n */\nexport async function submitRelayQuotes(\n request: PayStrategyExecuteRequest<RelayQuote>,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing quotes', request);\n\n const { quotes, messenger, transaction } = request;\n\n let transactionHash: Hex | undefined;\n\n for (const quote of quotes) {\n ({ transactionHash } = await executeSingleQuote(\n quote,\n messenger,\n transaction,\n ));\n }\n\n return { transactionHash };\n}\n\n/**\n * Executes a single Relay quote.\n *\n * @param quote - Relay quote to execute.\n * @param messenger - Controller messenger.\n * @param transaction - Original transaction meta.\n * @returns An object containing the transaction hash if available.\n */\nasync function executeSingleQuote(\n quote: TransactionPayQuote<RelayQuote>,\n messenger: TransactionPayControllerMessenger,\n transaction: TransactionMeta,\n): Promise<{ transactionHash?: Hex }> {\n log('Executing single quote', quote);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Remove nonce from skipped transaction',\n },\n (tx) => {\n tx.txParams.nonce = undefined;\n },\n );\n\n await submitTransactions(quote, transaction.id, messenger);\n\n const targetHash = await waitForRelayCompletion(quote.original);\n\n log('Relay request completed', targetHash);\n\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Intent complete after Relay completion',\n },\n (tx) => {\n tx.isIntentComplete = true;\n },\n );\n\n return { transactionHash: targetHash };\n}\n\n/**\n * Wait for a Relay request to complete.\n *\n * @param quote - Relay quote associated with the request.\n * @returns A promise that resolves when the Relay request is complete.\n */\nasync function waitForRelayCompletion(quote: RelayQuote): Promise<Hex> {\n const isSameChain =\n quote.details.currencyIn.currency.chainId ===\n quote.details.currencyOut.currency.chainId;\n\n const isSingleDepositStep =\n quote.steps.length === 1 && quote.steps[0].id === 'deposit';\n\n if (isSameChain && !isSingleDepositStep) {\n log('Skipping polling as same chain');\n return FALLBACK_HASH;\n }\n\n const { requestId } = quote.steps[0];\n const url = `${RELAY_STATUS_URL}?requestId=${requestId}`;\n\n while (true) {\n const response = await successfulFetch(url, { method: 'GET' });\n const status = (await response.json()) as RelayStatusResponse;\n\n log('Polled status', status.status, status);\n\n if (status.status === 'success') {\n const targetHash = status.txHashes?.slice(-1)[0] as Hex;\n return targetHash ?? FALLBACK_HASH;\n }\n\n if (['failure', 'refund', 'refunded'].includes(status.status)) {\n throw new Error(`Relay request failed with status: ${status.status}`);\n }\n\n await new Promise((resolve) => setTimeout(resolve, RELAY_POLLING_INTERVAL));\n }\n}\n\n/**\n * Normalize the parameters from a relay quote step to match TransactionParams.\n *\n * @param params - Parameters from a relay quote step.\n * @param messenger - Controller messenger.\n * @returns Normalized transaction parameters.\n */\nfunction normalizeParams(\n params: RelayQuote['steps'][0]['items'][0]['data'],\n messenger: TransactionPayControllerMessenger,\n): TransactionParams {\n const featureFlags = getFeatureFlags(messenger);\n\n return {\n data: params.data,\n from: params.from,\n gas: toHex(params.gas ?? featureFlags.relayFallbackGas.max),\n maxFeePerGas: toHex(params.maxFeePerGas),\n maxPriorityFeePerGas: toHex(params.maxPriorityFeePerGas),\n to: params.to,\n value: toHex(params.value ?? '0'),\n };\n}\n\n/**\n * Submit transactions for a relay quote.\n *\n * @param quote - Relay quote.\n * @param parentTransactionId - ID of the parent transaction.\n * @param messenger - Controller messenger.\n * @returns Hash of the last submitted transaction.\n */\nasync function submitTransactions(\n quote: TransactionPayQuote<RelayQuote>,\n parentTransactionId: string,\n messenger: TransactionPayControllerMessenger,\n): Promise<Hex> {\n const { steps } = quote.original;\n const params = steps.flatMap((step) => step.items).map((item) => item.data);\n const invalidKind = steps.find((step) => step.kind !== 'transaction')?.kind;\n\n if (invalidKind) {\n throw new Error(`Unsupported step kind: ${invalidKind}`);\n }\n\n const normalizedParams = params.map((singleParams) =>\n normalizeParams(singleParams, messenger),\n );\n\n const transactionIds: string[] = [];\n const { from, sourceChainId, sourceTokenAddress } = quote.request;\n\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n sourceChainId,\n );\n\n log('Adding transactions', {\n normalizedParams,\n sourceChainId,\n from,\n networkClientId,\n });\n\n const { end } = collectTransactionIds(\n sourceChainId,\n from,\n messenger,\n (transactionId) => {\n transactionIds.push(transactionId);\n\n updateTransaction(\n {\n transactionId: parentTransactionId,\n messenger,\n note: 'Add required transaction ID from Relay submission',\n },\n (tx) => {\n tx.requiredTransactionIds ??= [];\n tx.requiredTransactionIds.push(transactionId);\n },\n );\n },\n );\n\n let result: { result: Promise<string> } | undefined;\n\n const gasFeeToken = quote.fees.isSourceGasFeeToken\n ? sourceTokenAddress\n : undefined;\n\n const isSameChain =\n quote.original.details.currencyIn.currency.chainId ===\n quote.original.details.currencyOut.currency.chainId;\n\n const authorizationList: AuthorizationList | undefined =\n isSameChain && quote.original.request.authorizationList?.length\n ? quote.original.request.authorizationList.map((a) => ({\n address: a.address,\n chainId: toHex(a.chainId),\n }))\n : undefined;\n\n const { gasLimits } = quote.original.metamask;\n\n if (params.length === 1) {\n const transactionParams = {\n ...normalizedParams[0],\n authorizationList,\n gas: toHex(gasLimits[0]),\n };\n\n result = await messenger.call(\n 'TransactionController:addTransaction',\n transactionParams,\n {\n gasFeeToken,\n networkClientId,\n origin: ORIGIN_METAMASK,\n requireApproval: false,\n type: TransactionType.relayDeposit,\n },\n );\n } else {\n const gasLimit7702 =\n gasLimits.length === 1 ? toHex(gasLimits[0]) : undefined;\n\n const transactions = normalizedParams.map((singleParams, index) => ({\n params: {\n data: singleParams.data as Hex,\n gas: gasLimit7702 ? undefined : toHex(gasLimits[index]),\n maxFeePerGas: singleParams.maxFeePerGas as Hex,\n maxPriorityFeePerGas: singleParams.maxPriorityFeePerGas as Hex,\n to: singleParams.to as Hex,\n value: singleParams.value as Hex,\n },\n type:\n index === 0\n ? TransactionType.tokenMethodApprove\n : TransactionType.relayDeposit,\n }));\n\n await messenger.call('TransactionController:addTransactionBatch', {\n from,\n disable7702: !gasLimit7702,\n disableHook: Boolean(gasLimit7702),\n disableSequential: Boolean(gasLimit7702),\n gasFeeToken,\n gasLimit7702,\n networkClientId,\n origin: ORIGIN_METAMASK,\n overwriteUpgrade: true,\n requireApproval: false,\n transactions,\n });\n }\n\n end();\n\n log('Added transactions', transactionIds);\n\n if (result) {\n const txHash = await result.result;\n log('Submitted transaction', txHash);\n }\n\n await Promise.all(\n transactionIds.map((txId) => waitForTransactionConfirmed(txId, messenger)),\n );\n\n log('All transactions confirmed', transactionIds);\n\n const hash = getTransaction(transactionIds.slice(-1)[0], messenger)?.hash;\n\n return hash as Hex;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nexport type RelayQuoteRequest = {\n amount: string;\n authorizationList?: {\n address: Hex;\n chainId: number;\n nonce: number;\n r: Hex;\n s: Hex;\n yParity: number;\n }[];\n destinationChainId: number;\n destinationCurrency: Hex;\n originChainId: number;\n originCurrency: Hex;\n recipient: Hex;\n refundTo?: Hex;\n slippageTolerance?: string;\n tradeType: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';\n txs?: {\n to: Hex;\n data: Hex;\n value: Hex;\n }[];\n user: Hex;\n};\n\nexport type RelayQuote = {\n details: {\n currencyIn: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n };\n currencyOut: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n minimumAmount: string;\n };\n timeEstimate: number;\n totalImpact: {\n usd: string;\n };\n };\n fees: {\n relayer: {\n amountUsd: string;\n };\n };\n metamask: {\n gasLimits: number[];\n };\n request: RelayQuoteRequest;\n steps: {\n items: {\n check: {\n endpoint: string;\n method: 'GET' | 'POST';\n };\n data: {\n chainId: number;\n data: Hex;\n from: Hex;\n gas?: string;\n maxFeePerGas: string;\n maxPriorityFeePerGas: string;\n to: Hex;\n value?: string;\n };\n status: 'complete' | 'incomplete';\n }[];\n kind: 'transaction';\n requestId: string;\n }[];\n};\n\nexport type RelayStatus =\n | 'waiting'\n | 'pending'\n | 'submitted'\n | 'success'\n | 'delayed'\n | 'refunded'\n | 'refund'\n | 'failure';\n\nexport type RelayStatusResponse = {\n status: RelayStatus;\n inTxHashes: string[];\n txHashes: string[];\n updatedAt: number;\n originChainId: number;\n destinationChainId: number;\n};\n"]}
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nexport type RelayQuoteRequest = {\n amount: string;\n authorizationList?: {\n address: Hex;\n chainId: number;\n nonce: number;\n r: Hex;\n s: Hex;\n yParity: number;\n }[];\n destinationChainId: number;\n destinationCurrency: Hex;\n originChainId: number;\n originCurrency: Hex;\n recipient: Hex;\n refundTo?: Hex;\n slippageTolerance?: string;\n tradeType: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';\n txs?: {\n to: Hex;\n data: Hex;\n value: Hex;\n }[];\n user: Hex;\n};\n\nexport type RelayQuote = {\n details: {\n currencyIn: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n };\n currencyOut: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n minimumAmount: string;\n };\n timeEstimate: number;\n totalImpact: {\n usd: string;\n };\n };\n fees: {\n relayer: {\n amountUsd: string;\n };\n };\n metamask: {\n gasLimits: number[];\n };\n request: RelayQuoteRequest;\n steps: {\n id: string;\n items: {\n check: {\n endpoint: string;\n method: 'GET' | 'POST';\n };\n data: {\n chainId: number;\n data: Hex;\n from: Hex;\n gas?: string;\n maxFeePerGas: string;\n maxPriorityFeePerGas: string;\n to: Hex;\n value?: string;\n };\n status: 'complete' | 'incomplete';\n }[];\n kind: 'transaction';\n requestId: string;\n }[];\n};\n\nexport type RelayStatus =\n | 'waiting'\n | 'pending'\n | 'submitted'\n | 'success'\n | 'delayed'\n | 'refunded'\n | 'refund'\n | 'failure';\n\nexport type RelayStatusResponse = {\n status: RelayStatus;\n inTxHashes: string[];\n txHashes: string[];\n updatedAt: number;\n originChainId: number;\n destinationChainId: number;\n};\n"]}
@@ -60,6 +60,7 @@ export type RelayQuote = {
60
60
  };
61
61
  request: RelayQuoteRequest;
62
62
  steps: {
63
+ id: string;
63
64
  items: {
64
65
  check: {
65
66
  endpoint: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"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"}
@@ -60,6 +60,7 @@ export type RelayQuote = {
60
60
  };
61
61
  request: RelayQuoteRequest;
62
62
  steps: {
63
+ id: string;
63
64
  items: {
64
65
  check: {
65
66
  endpoint: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nexport type RelayQuoteRequest = {\n amount: string;\n authorizationList?: {\n address: Hex;\n chainId: number;\n nonce: number;\n r: Hex;\n s: Hex;\n yParity: number;\n }[];\n destinationChainId: number;\n destinationCurrency: Hex;\n originChainId: number;\n originCurrency: Hex;\n recipient: Hex;\n refundTo?: Hex;\n slippageTolerance?: string;\n tradeType: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';\n txs?: {\n to: Hex;\n data: Hex;\n value: Hex;\n }[];\n user: Hex;\n};\n\nexport type RelayQuote = {\n details: {\n currencyIn: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n };\n currencyOut: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n minimumAmount: string;\n };\n timeEstimate: number;\n totalImpact: {\n usd: string;\n };\n };\n fees: {\n relayer: {\n amountUsd: string;\n };\n };\n metamask: {\n gasLimits: number[];\n };\n request: RelayQuoteRequest;\n steps: {\n items: {\n check: {\n endpoint: string;\n method: 'GET' | 'POST';\n };\n data: {\n chainId: number;\n data: Hex;\n from: Hex;\n gas?: string;\n maxFeePerGas: string;\n maxPriorityFeePerGas: string;\n to: Hex;\n value?: string;\n };\n status: 'complete' | 'incomplete';\n }[];\n kind: 'transaction';\n requestId: string;\n }[];\n};\n\nexport type RelayStatus =\n | 'waiting'\n | 'pending'\n | 'submitted'\n | 'success'\n | 'delayed'\n | 'refunded'\n | 'refund'\n | 'failure';\n\nexport type RelayStatusResponse = {\n status: RelayStatus;\n inTxHashes: string[];\n txHashes: string[];\n updatedAt: number;\n originChainId: number;\n destinationChainId: number;\n};\n"]}
1
+ {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nexport type RelayQuoteRequest = {\n amount: string;\n authorizationList?: {\n address: Hex;\n chainId: number;\n nonce: number;\n r: Hex;\n s: Hex;\n yParity: number;\n }[];\n destinationChainId: number;\n destinationCurrency: Hex;\n originChainId: number;\n originCurrency: Hex;\n recipient: Hex;\n refundTo?: Hex;\n slippageTolerance?: string;\n tradeType: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';\n txs?: {\n to: Hex;\n data: Hex;\n value: Hex;\n }[];\n user: Hex;\n};\n\nexport type RelayQuote = {\n details: {\n currencyIn: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n };\n currencyOut: {\n amount: string;\n amountFormatted: string;\n amountUsd: string;\n currency: {\n chainId: number;\n decimals: number;\n };\n minimumAmount: string;\n };\n timeEstimate: number;\n totalImpact: {\n usd: string;\n };\n };\n fees: {\n relayer: {\n amountUsd: string;\n };\n };\n metamask: {\n gasLimits: number[];\n };\n request: RelayQuoteRequest;\n steps: {\n id: string;\n items: {\n check: {\n endpoint: string;\n method: 'GET' | 'POST';\n };\n data: {\n chainId: number;\n data: Hex;\n from: Hex;\n gas?: string;\n maxFeePerGas: string;\n maxPriorityFeePerGas: string;\n to: Hex;\n value?: string;\n };\n status: 'complete' | 'incomplete';\n }[];\n kind: 'transaction';\n requestId: string;\n }[];\n};\n\nexport type RelayStatus =\n | 'waiting'\n | 'pending'\n | 'submitted'\n | 'success'\n | 'delayed'\n | 'refunded'\n | 'refund'\n | 'failure';\n\nexport type RelayStatusResponse = {\n status: RelayStatus;\n inTxHashes: string[];\n txHashes: string[];\n updatedAt: number;\n originChainId: number;\n destinationChainId: number;\n};\n"]}
@@ -11,11 +11,21 @@ const FOUR_BYTE_TOKEN_TRANSFER = '0xa9059cbb';
11
11
  /**
12
12
  * Parse required tokens from a transaction.
13
13
  *
14
+ * If the transaction has `requiredAssets`, those are used to determine required tokens.
15
+ * Otherwise, falls back to parsing the transaction data for token transfers.
16
+ *
14
17
  * @param transaction - Transaction metadata.
15
18
  * @param messenger - Controller messenger.
16
19
  * @returns An array of required tokens.
17
20
  */
18
21
  function parseRequiredTokens(transaction, messenger) {
22
+ const { requiredAssets } = transaction;
23
+ if (requiredAssets?.length) {
24
+ const assetTokens = requiredAssets
25
+ .map((asset) => buildRequiredToken(transaction, asset.address, asset.amount, messenger))
26
+ .filter(Boolean);
27
+ return assetTokens;
28
+ }
19
29
  return [
20
30
  getTokenTransferToken(transaction, messenger),
21
31
  getGasFeeToken(transaction, messenger),
@@ -1 +1 @@
1
- {"version":3,"file":"required-tokens.cjs","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenFiatRate,\n getTokenInfo,\n} from './token';\nimport type {\n FiatRates,\n TransactionPayControllerMessenger,\n TransactionPayRequiredToken,\n} from '../types';\n\nconst FOUR_BYTE_TOKEN_TRANSFER = '0xa9059cbb';\n\n/**\n * Parse required tokens from a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns An array of required tokens.\n */\nexport function parseRequiredTokens(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken[] {\n return [\n getTokenTransferToken(transaction, messenger),\n getGasFeeToken(transaction, messenger),\n ].filter(Boolean) as TransactionPayRequiredToken[];\n}\n\n/**\n * Parse a required token from a token transfer.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The required token or undefined if the transaction is not a token transfer.\n */\nfunction getTokenTransferToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { data, to } = getTokenTransferData(transaction) ?? {};\n\n if (!to || !data) {\n return undefined;\n }\n\n let transferAmount: Hex | undefined;\n\n try {\n const result = new Interface(abiERC20).decodeFunctionData('transfer', data);\n transferAmount = toHex(result._value);\n } catch {\n // Intentionally empty\n }\n\n if (transferAmount === undefined) {\n return undefined;\n }\n\n return buildRequiredToken(transaction, to, transferAmount, messenger);\n}\n\n/**\n * Get the gas fee token required for a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The gas fee token or undefined if it could not be determined.\n */\nfunction getGasFeeToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const { gas, maxFeePerGas } = txParams;\n const nativeTokenAddress = getNativeToken(chainId);\n\n const maxGasCostRawHex = add0x(\n new BigNumber(gas ?? '0x0')\n .multipliedBy(new BigNumber(maxFeePerGas ?? '0x0'))\n .toString(16),\n );\n\n const token = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n maxGasCostRawHex,\n messenger,\n );\n\n if (!token) {\n return undefined;\n }\n\n const amountUsdValue = new BigNumber(token.amountUsd);\n\n const hasBalance = new BigNumber(token.balanceRaw).isGreaterThanOrEqualTo(\n token.amountRaw,\n );\n\n if (hasBalance || amountUsdValue.isGreaterThanOrEqualTo(1)) {\n return {\n ...token,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n }\n\n const fiatRates = getTokenFiatRate(\n messenger,\n nativeTokenAddress,\n chainId,\n ) as FiatRates;\n\n const oneDollarRawHex = add0x(\n new BigNumber(1).dividedBy(fiatRates.usdRate).shiftedBy(18).toString(16),\n );\n\n const oneDollarToken = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n oneDollarRawHex,\n messenger,\n );\n\n /* istanbul ignore next */\n if (!oneDollarToken) {\n return undefined;\n }\n\n return {\n ...oneDollarToken,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n}\n\n/**\n * Get the full token properties for a specific token and amount.\n *\n * @param transaction - Transaction metadata.\n * @param tokenAddress - Token address.\n * @param amountRawHex - Raw token amount in hexadecimal format.\n * @param messenger - Controller messenger.\n * @returns The full token properties or undefined if the token data could not be retrieved.\n */\nfunction buildRequiredToken(\n transaction: TransactionMeta,\n tokenAddress: Hex,\n amountRawHex: Hex,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const from = txParams.from as Hex;\n\n const { decimals: tokenDecimals, symbol } =\n getTokenInfo(messenger, tokenAddress, chainId) ?? {};\n\n const fiatRates = getTokenFiatRate(messenger, tokenAddress, chainId);\n const tokenBalance = getTokenBalance(messenger, from, chainId, tokenAddress);\n\n if (tokenDecimals === undefined || !symbol || fiatRates === undefined) {\n return undefined;\n }\n\n const {\n amountHuman: balanceHuman,\n amountRaw: balanceRaw,\n amountFiat: balanceFiat,\n amountUsd: balanceUsd,\n } = calculateAmounts(tokenBalance, tokenDecimals, fiatRates);\n\n const { amountHuman, amountRaw, amountFiat, amountUsd } = calculateAmounts(\n amountRawHex,\n tokenDecimals,\n fiatRates,\n );\n\n return {\n address: tokenAddress,\n allowUnderMinimum: false,\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n balanceFiat,\n balanceHuman,\n balanceRaw,\n balanceUsd,\n chainId,\n decimals: tokenDecimals,\n skipIfBalance: false,\n symbol,\n };\n}\n\n/**\n * Calculates the various amount representations for a token value.\n *\n * @param amountRawInput - Raw amount.\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing amount in fiat, human-readable, raw, and USD formats.\n */\nfunction calculateAmounts(\n amountRawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n amountFiat: string;\n amountHuman: string;\n amountRaw: string;\n amountUsd: string;\n} {\n const amountRawValue = new BigNumber(amountRawInput);\n const amountHumanValue = amountRawValue.shiftedBy(-decimals);\n\n const amountFiat = amountHumanValue\n .multipliedBy(fiatRates.fiatRate)\n .toString(10);\n\n const amountUsd = amountHumanValue\n .multipliedBy(fiatRates.usdRate)\n .toString(10);\n\n const amountRaw = amountRawValue.toFixed(0);\n const amountHuman = amountHumanValue.toString(10);\n\n return {\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n };\n}\n\n/**\n * Find token transfer data in a transaction.\n *\n * @param transactionMeta - Transaction metadata.\n * @returns - Token transfer data or undefined if not found.\n */\nfunction getTokenTransferData(transactionMeta: TransactionMeta):\n | {\n data: Hex;\n to: Hex;\n index?: number;\n }\n | undefined {\n const { nestedTransactions, txParams } = transactionMeta;\n const { data: singleData } = txParams;\n const singleTo = txParams?.to as Hex | undefined;\n\n if (singleData?.startsWith(FOUR_BYTE_TOKEN_TRANSFER) && singleTo) {\n return { data: singleData as Hex, to: singleTo, index: undefined };\n }\n\n const nestedCallIndex = nestedTransactions?.findIndex((call) =>\n call.data?.startsWith(FOUR_BYTE_TOKEN_TRANSFER),\n );\n\n const nestedCall =\n nestedCallIndex === undefined\n ? undefined\n : nestedTransactions?.[nestedCallIndex];\n\n if (nestedCall?.data && nestedCall.to) {\n return {\n data: nestedCall.data,\n to: nestedCall.to,\n index: nestedCallIndex,\n };\n }\n\n return undefined;\n}\n"]}
1
+ {"version":3,"file":"required-tokens.cjs","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenFiatRate,\n getTokenInfo,\n} from './token';\nimport type {\n FiatRates,\n TransactionPayControllerMessenger,\n TransactionPayRequiredToken,\n} from '../types';\n\nconst FOUR_BYTE_TOKEN_TRANSFER = '0xa9059cbb';\n\n/**\n * Parse required tokens from a transaction.\n *\n * If the transaction has `requiredAssets`, those are used to determine required tokens.\n * Otherwise, falls back to parsing the transaction data for token transfers.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns An array of required tokens.\n */\nexport function parseRequiredTokens(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken[] {\n const { requiredAssets } = transaction;\n\n if (requiredAssets?.length) {\n const assetTokens = requiredAssets\n .map((asset) =>\n buildRequiredToken(transaction, asset.address, asset.amount, messenger),\n )\n .filter(Boolean) as TransactionPayRequiredToken[];\n\n return assetTokens;\n }\n\n return [\n getTokenTransferToken(transaction, messenger),\n getGasFeeToken(transaction, messenger),\n ].filter(Boolean) as TransactionPayRequiredToken[];\n}\n\n/**\n * Parse a required token from a token transfer.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The required token or undefined if the transaction is not a token transfer.\n */\nfunction getTokenTransferToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { data, to } = getTokenTransferData(transaction) ?? {};\n\n if (!to || !data) {\n return undefined;\n }\n\n let transferAmount: Hex | undefined;\n\n try {\n const result = new Interface(abiERC20).decodeFunctionData('transfer', data);\n transferAmount = toHex(result._value);\n } catch {\n // Intentionally empty\n }\n\n if (transferAmount === undefined) {\n return undefined;\n }\n\n return buildRequiredToken(transaction, to, transferAmount, messenger);\n}\n\n/**\n * Get the gas fee token required for a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The gas fee token or undefined if it could not be determined.\n */\nfunction getGasFeeToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const { gas, maxFeePerGas } = txParams;\n const nativeTokenAddress = getNativeToken(chainId);\n\n const maxGasCostRawHex = add0x(\n new BigNumber(gas ?? '0x0')\n .multipliedBy(new BigNumber(maxFeePerGas ?? '0x0'))\n .toString(16),\n );\n\n const token = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n maxGasCostRawHex,\n messenger,\n );\n\n if (!token) {\n return undefined;\n }\n\n const amountUsdValue = new BigNumber(token.amountUsd);\n\n const hasBalance = new BigNumber(token.balanceRaw).isGreaterThanOrEqualTo(\n token.amountRaw,\n );\n\n if (hasBalance || amountUsdValue.isGreaterThanOrEqualTo(1)) {\n return {\n ...token,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n }\n\n const fiatRates = getTokenFiatRate(\n messenger,\n nativeTokenAddress,\n chainId,\n ) as FiatRates;\n\n const oneDollarRawHex = add0x(\n new BigNumber(1).dividedBy(fiatRates.usdRate).shiftedBy(18).toString(16),\n );\n\n const oneDollarToken = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n oneDollarRawHex,\n messenger,\n );\n\n /* istanbul ignore next */\n if (!oneDollarToken) {\n return undefined;\n }\n\n return {\n ...oneDollarToken,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n}\n\n/**\n * Get the full token properties for a specific token and amount.\n *\n * @param transaction - Transaction metadata.\n * @param tokenAddress - Token address.\n * @param amountRawHex - Raw token amount in hexadecimal format.\n * @param messenger - Controller messenger.\n * @returns The full token properties or undefined if the token data could not be retrieved.\n */\nfunction buildRequiredToken(\n transaction: TransactionMeta,\n tokenAddress: Hex,\n amountRawHex: Hex,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const from = txParams.from as Hex;\n\n const { decimals: tokenDecimals, symbol } =\n getTokenInfo(messenger, tokenAddress, chainId) ?? {};\n\n const fiatRates = getTokenFiatRate(messenger, tokenAddress, chainId);\n const tokenBalance = getTokenBalance(messenger, from, chainId, tokenAddress);\n\n if (tokenDecimals === undefined || !symbol || fiatRates === undefined) {\n return undefined;\n }\n\n const {\n amountHuman: balanceHuman,\n amountRaw: balanceRaw,\n amountFiat: balanceFiat,\n amountUsd: balanceUsd,\n } = calculateAmounts(tokenBalance, tokenDecimals, fiatRates);\n\n const { amountHuman, amountRaw, amountFiat, amountUsd } = calculateAmounts(\n amountRawHex,\n tokenDecimals,\n fiatRates,\n );\n\n return {\n address: tokenAddress,\n allowUnderMinimum: false,\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n balanceFiat,\n balanceHuman,\n balanceRaw,\n balanceUsd,\n chainId,\n decimals: tokenDecimals,\n skipIfBalance: false,\n symbol,\n };\n}\n\n/**\n * Calculates the various amount representations for a token value.\n *\n * @param amountRawInput - Raw amount.\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing amount in fiat, human-readable, raw, and USD formats.\n */\nfunction calculateAmounts(\n amountRawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n amountFiat: string;\n amountHuman: string;\n amountRaw: string;\n amountUsd: string;\n} {\n const amountRawValue = new BigNumber(amountRawInput);\n const amountHumanValue = amountRawValue.shiftedBy(-decimals);\n\n const amountFiat = amountHumanValue\n .multipliedBy(fiatRates.fiatRate)\n .toString(10);\n\n const amountUsd = amountHumanValue\n .multipliedBy(fiatRates.usdRate)\n .toString(10);\n\n const amountRaw = amountRawValue.toFixed(0);\n const amountHuman = amountHumanValue.toString(10);\n\n return {\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n };\n}\n\n/**\n * Find token transfer data in a transaction.\n *\n * @param transactionMeta - Transaction metadata.\n * @returns - Token transfer data or undefined if not found.\n */\nfunction getTokenTransferData(transactionMeta: TransactionMeta):\n | {\n data: Hex;\n to: Hex;\n index?: number;\n }\n | undefined {\n const { nestedTransactions, txParams } = transactionMeta;\n const { data: singleData } = txParams;\n const singleTo = txParams?.to as Hex | undefined;\n\n if (singleData?.startsWith(FOUR_BYTE_TOKEN_TRANSFER) && singleTo) {\n return { data: singleData as Hex, to: singleTo, index: undefined };\n }\n\n const nestedCallIndex = nestedTransactions?.findIndex((call) =>\n call.data?.startsWith(FOUR_BYTE_TOKEN_TRANSFER),\n );\n\n const nestedCall =\n nestedCallIndex === undefined\n ? undefined\n : nestedTransactions?.[nestedCallIndex];\n\n if (nestedCall?.data && nestedCall.to) {\n return {\n data: nestedCall.data,\n to: nestedCall.to,\n index: nestedCallIndex,\n };\n }\n\n return undefined;\n}\n"]}
@@ -3,6 +3,9 @@ import type { TransactionPayControllerMessenger, TransactionPayRequiredToken } f
3
3
  /**
4
4
  * Parse required tokens from a transaction.
5
5
  *
6
+ * If the transaction has `requiredAssets`, those are used to determine required tokens.
7
+ * Otherwise, falls back to parsing the transaction data for token transfers.
8
+ *
6
9
  * @param transaction - Transaction metadata.
7
10
  * @param messenger - Controller messenger.
8
11
  * @returns An array of required tokens.
@@ -1 +1 @@
1
- {"version":3,"file":"required-tokens.d.cts","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAEV,iCAAiC,EACjC,2BAA2B,EAC5B,qBAAiB;AAIlB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,iCAAiC,GAC3C,2BAA2B,EAAE,CAK/B"}
1
+ {"version":3,"file":"required-tokens.d.cts","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAEV,iCAAiC,EACjC,2BAA2B,EAC5B,qBAAiB;AAIlB;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,iCAAiC,GAC3C,2BAA2B,EAAE,CAiB/B"}
@@ -3,6 +3,9 @@ import type { TransactionPayControllerMessenger, TransactionPayRequiredToken } f
3
3
  /**
4
4
  * Parse required tokens from a transaction.
5
5
  *
6
+ * If the transaction has `requiredAssets`, those are used to determine required tokens.
7
+ * Otherwise, falls back to parsing the transaction data for token transfers.
8
+ *
6
9
  * @param transaction - Transaction metadata.
7
10
  * @param messenger - Controller messenger.
8
11
  * @returns An array of required tokens.
@@ -1 +1 @@
1
- {"version":3,"file":"required-tokens.d.mts","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAEV,iCAAiC,EACjC,2BAA2B,EAC5B,qBAAiB;AAIlB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,iCAAiC,GAC3C,2BAA2B,EAAE,CAK/B"}
1
+ {"version":3,"file":"required-tokens.d.mts","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAEV,iCAAiC,EACjC,2BAA2B,EAC5B,qBAAiB;AAIlB;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,iCAAiC,GAC3C,2BAA2B,EAAE,CAiB/B"}
@@ -8,11 +8,21 @@ const FOUR_BYTE_TOKEN_TRANSFER = '0xa9059cbb';
8
8
  /**
9
9
  * Parse required tokens from a transaction.
10
10
  *
11
+ * If the transaction has `requiredAssets`, those are used to determine required tokens.
12
+ * Otherwise, falls back to parsing the transaction data for token transfers.
13
+ *
11
14
  * @param transaction - Transaction metadata.
12
15
  * @param messenger - Controller messenger.
13
16
  * @returns An array of required tokens.
14
17
  */
15
18
  export function parseRequiredTokens(transaction, messenger) {
19
+ const { requiredAssets } = transaction;
20
+ if (requiredAssets?.length) {
21
+ const assetTokens = requiredAssets
22
+ .map((asset) => buildRequiredToken(transaction, asset.address, asset.amount, messenger))
23
+ .filter(Boolean);
24
+ return assetTokens;
25
+ }
16
26
  return [
17
27
  getTokenTransferToken(transaction, messenger),
18
28
  getGasFeeToken(transaction, messenger),
@@ -1 +1 @@
1
- {"version":3,"file":"required-tokens.mjs","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenFiatRate,\n getTokenInfo,\n} from './token';\nimport type {\n FiatRates,\n TransactionPayControllerMessenger,\n TransactionPayRequiredToken,\n} from '../types';\n\nconst FOUR_BYTE_TOKEN_TRANSFER = '0xa9059cbb';\n\n/**\n * Parse required tokens from a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns An array of required tokens.\n */\nexport function parseRequiredTokens(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken[] {\n return [\n getTokenTransferToken(transaction, messenger),\n getGasFeeToken(transaction, messenger),\n ].filter(Boolean) as TransactionPayRequiredToken[];\n}\n\n/**\n * Parse a required token from a token transfer.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The required token or undefined if the transaction is not a token transfer.\n */\nfunction getTokenTransferToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { data, to } = getTokenTransferData(transaction) ?? {};\n\n if (!to || !data) {\n return undefined;\n }\n\n let transferAmount: Hex | undefined;\n\n try {\n const result = new Interface(abiERC20).decodeFunctionData('transfer', data);\n transferAmount = toHex(result._value);\n } catch {\n // Intentionally empty\n }\n\n if (transferAmount === undefined) {\n return undefined;\n }\n\n return buildRequiredToken(transaction, to, transferAmount, messenger);\n}\n\n/**\n * Get the gas fee token required for a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The gas fee token or undefined if it could not be determined.\n */\nfunction getGasFeeToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const { gas, maxFeePerGas } = txParams;\n const nativeTokenAddress = getNativeToken(chainId);\n\n const maxGasCostRawHex = add0x(\n new BigNumber(gas ?? '0x0')\n .multipliedBy(new BigNumber(maxFeePerGas ?? '0x0'))\n .toString(16),\n );\n\n const token = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n maxGasCostRawHex,\n messenger,\n );\n\n if (!token) {\n return undefined;\n }\n\n const amountUsdValue = new BigNumber(token.amountUsd);\n\n const hasBalance = new BigNumber(token.balanceRaw).isGreaterThanOrEqualTo(\n token.amountRaw,\n );\n\n if (hasBalance || amountUsdValue.isGreaterThanOrEqualTo(1)) {\n return {\n ...token,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n }\n\n const fiatRates = getTokenFiatRate(\n messenger,\n nativeTokenAddress,\n chainId,\n ) as FiatRates;\n\n const oneDollarRawHex = add0x(\n new BigNumber(1).dividedBy(fiatRates.usdRate).shiftedBy(18).toString(16),\n );\n\n const oneDollarToken = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n oneDollarRawHex,\n messenger,\n );\n\n /* istanbul ignore next */\n if (!oneDollarToken) {\n return undefined;\n }\n\n return {\n ...oneDollarToken,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n}\n\n/**\n * Get the full token properties for a specific token and amount.\n *\n * @param transaction - Transaction metadata.\n * @param tokenAddress - Token address.\n * @param amountRawHex - Raw token amount in hexadecimal format.\n * @param messenger - Controller messenger.\n * @returns The full token properties or undefined if the token data could not be retrieved.\n */\nfunction buildRequiredToken(\n transaction: TransactionMeta,\n tokenAddress: Hex,\n amountRawHex: Hex,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const from = txParams.from as Hex;\n\n const { decimals: tokenDecimals, symbol } =\n getTokenInfo(messenger, tokenAddress, chainId) ?? {};\n\n const fiatRates = getTokenFiatRate(messenger, tokenAddress, chainId);\n const tokenBalance = getTokenBalance(messenger, from, chainId, tokenAddress);\n\n if (tokenDecimals === undefined || !symbol || fiatRates === undefined) {\n return undefined;\n }\n\n const {\n amountHuman: balanceHuman,\n amountRaw: balanceRaw,\n amountFiat: balanceFiat,\n amountUsd: balanceUsd,\n } = calculateAmounts(tokenBalance, tokenDecimals, fiatRates);\n\n const { amountHuman, amountRaw, amountFiat, amountUsd } = calculateAmounts(\n amountRawHex,\n tokenDecimals,\n fiatRates,\n );\n\n return {\n address: tokenAddress,\n allowUnderMinimum: false,\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n balanceFiat,\n balanceHuman,\n balanceRaw,\n balanceUsd,\n chainId,\n decimals: tokenDecimals,\n skipIfBalance: false,\n symbol,\n };\n}\n\n/**\n * Calculates the various amount representations for a token value.\n *\n * @param amountRawInput - Raw amount.\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing amount in fiat, human-readable, raw, and USD formats.\n */\nfunction calculateAmounts(\n amountRawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n amountFiat: string;\n amountHuman: string;\n amountRaw: string;\n amountUsd: string;\n} {\n const amountRawValue = new BigNumber(amountRawInput);\n const amountHumanValue = amountRawValue.shiftedBy(-decimals);\n\n const amountFiat = amountHumanValue\n .multipliedBy(fiatRates.fiatRate)\n .toString(10);\n\n const amountUsd = amountHumanValue\n .multipliedBy(fiatRates.usdRate)\n .toString(10);\n\n const amountRaw = amountRawValue.toFixed(0);\n const amountHuman = amountHumanValue.toString(10);\n\n return {\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n };\n}\n\n/**\n * Find token transfer data in a transaction.\n *\n * @param transactionMeta - Transaction metadata.\n * @returns - Token transfer data or undefined if not found.\n */\nfunction getTokenTransferData(transactionMeta: TransactionMeta):\n | {\n data: Hex;\n to: Hex;\n index?: number;\n }\n | undefined {\n const { nestedTransactions, txParams } = transactionMeta;\n const { data: singleData } = txParams;\n const singleTo = txParams?.to as Hex | undefined;\n\n if (singleData?.startsWith(FOUR_BYTE_TOKEN_TRANSFER) && singleTo) {\n return { data: singleData as Hex, to: singleTo, index: undefined };\n }\n\n const nestedCallIndex = nestedTransactions?.findIndex((call) =>\n call.data?.startsWith(FOUR_BYTE_TOKEN_TRANSFER),\n );\n\n const nestedCall =\n nestedCallIndex === undefined\n ? undefined\n : nestedTransactions?.[nestedCallIndex];\n\n if (nestedCall?.data && nestedCall.to) {\n return {\n data: nestedCall.data,\n to: nestedCall.to,\n index: nestedCallIndex,\n };\n }\n\n return undefined;\n}\n"]}
1
+ {"version":3,"file":"required-tokens.mjs","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenFiatRate,\n getTokenInfo,\n} from './token';\nimport type {\n FiatRates,\n TransactionPayControllerMessenger,\n TransactionPayRequiredToken,\n} from '../types';\n\nconst FOUR_BYTE_TOKEN_TRANSFER = '0xa9059cbb';\n\n/**\n * Parse required tokens from a transaction.\n *\n * If the transaction has `requiredAssets`, those are used to determine required tokens.\n * Otherwise, falls back to parsing the transaction data for token transfers.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns An array of required tokens.\n */\nexport function parseRequiredTokens(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken[] {\n const { requiredAssets } = transaction;\n\n if (requiredAssets?.length) {\n const assetTokens = requiredAssets\n .map((asset) =>\n buildRequiredToken(transaction, asset.address, asset.amount, messenger),\n )\n .filter(Boolean) as TransactionPayRequiredToken[];\n\n return assetTokens;\n }\n\n return [\n getTokenTransferToken(transaction, messenger),\n getGasFeeToken(transaction, messenger),\n ].filter(Boolean) as TransactionPayRequiredToken[];\n}\n\n/**\n * Parse a required token from a token transfer.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The required token or undefined if the transaction is not a token transfer.\n */\nfunction getTokenTransferToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { data, to } = getTokenTransferData(transaction) ?? {};\n\n if (!to || !data) {\n return undefined;\n }\n\n let transferAmount: Hex | undefined;\n\n try {\n const result = new Interface(abiERC20).decodeFunctionData('transfer', data);\n transferAmount = toHex(result._value);\n } catch {\n // Intentionally empty\n }\n\n if (transferAmount === undefined) {\n return undefined;\n }\n\n return buildRequiredToken(transaction, to, transferAmount, messenger);\n}\n\n/**\n * Get the gas fee token required for a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The gas fee token or undefined if it could not be determined.\n */\nfunction getGasFeeToken(\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const { gas, maxFeePerGas } = txParams;\n const nativeTokenAddress = getNativeToken(chainId);\n\n const maxGasCostRawHex = add0x(\n new BigNumber(gas ?? '0x0')\n .multipliedBy(new BigNumber(maxFeePerGas ?? '0x0'))\n .toString(16),\n );\n\n const token = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n maxGasCostRawHex,\n messenger,\n );\n\n if (!token) {\n return undefined;\n }\n\n const amountUsdValue = new BigNumber(token.amountUsd);\n\n const hasBalance = new BigNumber(token.balanceRaw).isGreaterThanOrEqualTo(\n token.amountRaw,\n );\n\n if (hasBalance || amountUsdValue.isGreaterThanOrEqualTo(1)) {\n return {\n ...token,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n }\n\n const fiatRates = getTokenFiatRate(\n messenger,\n nativeTokenAddress,\n chainId,\n ) as FiatRates;\n\n const oneDollarRawHex = add0x(\n new BigNumber(1).dividedBy(fiatRates.usdRate).shiftedBy(18).toString(16),\n );\n\n const oneDollarToken = buildRequiredToken(\n transaction,\n nativeTokenAddress,\n oneDollarRawHex,\n messenger,\n );\n\n /* istanbul ignore next */\n if (!oneDollarToken) {\n return undefined;\n }\n\n return {\n ...oneDollarToken,\n allowUnderMinimum: true,\n skipIfBalance: true,\n };\n}\n\n/**\n * Get the full token properties for a specific token and amount.\n *\n * @param transaction - Transaction metadata.\n * @param tokenAddress - Token address.\n * @param amountRawHex - Raw token amount in hexadecimal format.\n * @param messenger - Controller messenger.\n * @returns The full token properties or undefined if the token data could not be retrieved.\n */\nfunction buildRequiredToken(\n transaction: TransactionMeta,\n tokenAddress: Hex,\n amountRawHex: Hex,\n messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n const { chainId, txParams } = transaction;\n const from = txParams.from as Hex;\n\n const { decimals: tokenDecimals, symbol } =\n getTokenInfo(messenger, tokenAddress, chainId) ?? {};\n\n const fiatRates = getTokenFiatRate(messenger, tokenAddress, chainId);\n const tokenBalance = getTokenBalance(messenger, from, chainId, tokenAddress);\n\n if (tokenDecimals === undefined || !symbol || fiatRates === undefined) {\n return undefined;\n }\n\n const {\n amountHuman: balanceHuman,\n amountRaw: balanceRaw,\n amountFiat: balanceFiat,\n amountUsd: balanceUsd,\n } = calculateAmounts(tokenBalance, tokenDecimals, fiatRates);\n\n const { amountHuman, amountRaw, amountFiat, amountUsd } = calculateAmounts(\n amountRawHex,\n tokenDecimals,\n fiatRates,\n );\n\n return {\n address: tokenAddress,\n allowUnderMinimum: false,\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n balanceFiat,\n balanceHuman,\n balanceRaw,\n balanceUsd,\n chainId,\n decimals: tokenDecimals,\n skipIfBalance: false,\n symbol,\n };\n}\n\n/**\n * Calculates the various amount representations for a token value.\n *\n * @param amountRawInput - Raw amount.\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing amount in fiat, human-readable, raw, and USD formats.\n */\nfunction calculateAmounts(\n amountRawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n amountFiat: string;\n amountHuman: string;\n amountRaw: string;\n amountUsd: string;\n} {\n const amountRawValue = new BigNumber(amountRawInput);\n const amountHumanValue = amountRawValue.shiftedBy(-decimals);\n\n const amountFiat = amountHumanValue\n .multipliedBy(fiatRates.fiatRate)\n .toString(10);\n\n const amountUsd = amountHumanValue\n .multipliedBy(fiatRates.usdRate)\n .toString(10);\n\n const amountRaw = amountRawValue.toFixed(0);\n const amountHuman = amountHumanValue.toString(10);\n\n return {\n amountFiat,\n amountHuman,\n amountRaw,\n amountUsd,\n };\n}\n\n/**\n * Find token transfer data in a transaction.\n *\n * @param transactionMeta - Transaction metadata.\n * @returns - Token transfer data or undefined if not found.\n */\nfunction getTokenTransferData(transactionMeta: TransactionMeta):\n | {\n data: Hex;\n to: Hex;\n index?: number;\n }\n | undefined {\n const { nestedTransactions, txParams } = transactionMeta;\n const { data: singleData } = txParams;\n const singleTo = txParams?.to as Hex | undefined;\n\n if (singleData?.startsWith(FOUR_BYTE_TOKEN_TRANSFER) && singleTo) {\n return { data: singleData as Hex, to: singleTo, index: undefined };\n }\n\n const nestedCallIndex = nestedTransactions?.findIndex((call) =>\n call.data?.startsWith(FOUR_BYTE_TOKEN_TRANSFER),\n );\n\n const nestedCall =\n nestedCallIndex === undefined\n ? undefined\n : nestedTransactions?.[nestedCallIndex];\n\n if (nestedCall?.data && nestedCall.to) {\n return {\n data: nestedCall.data,\n to: nestedCall.to,\n index: nestedCallIndex,\n };\n }\n\n return undefined;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/transaction-pay-controller",
3
- "version": "12.0.2",
3
+ "version": "12.2.0",
4
4
  "description": "Manages alternate payment strategies to provide required funds for transactions in MetaMask",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -51,17 +51,17 @@
51
51
  "dependencies": {
52
52
  "@ethersproject/abi": "^5.7.0",
53
53
  "@ethersproject/contracts": "^5.7.0",
54
- "@metamask/assets-controllers": "^99.1.0",
54
+ "@metamask/assets-controllers": "^99.2.0",
55
55
  "@metamask/base-controller": "^9.0.0",
56
- "@metamask/bridge-controller": "^65.1.0",
57
- "@metamask/bridge-status-controller": "^65.0.1",
56
+ "@metamask/bridge-controller": "^65.3.0",
57
+ "@metamask/bridge-status-controller": "^66.0.0",
58
58
  "@metamask/controller-utils": "^11.18.0",
59
59
  "@metamask/gas-fee-controller": "^26.0.2",
60
60
  "@metamask/messenger": "^0.3.0",
61
61
  "@metamask/metamask-eth-abis": "^3.1.1",
62
62
  "@metamask/network-controller": "^29.0.0",
63
63
  "@metamask/remote-feature-flag-controller": "^4.0.0",
64
- "@metamask/transaction-controller": "^62.11.0",
64
+ "@metamask/transaction-controller": "^62.14.0",
65
65
  "@metamask/utils": "^11.9.0",
66
66
  "bignumber.js": "^9.1.2",
67
67
  "bn.js": "^5.2.1",
@@ -71,10 +71,10 @@
71
71
  "devDependencies": {
72
72
  "@metamask/auto-changelog": "^3.4.4",
73
73
  "@ts-bridge/cli": "^0.6.4",
74
- "@types/jest": "^27.4.1",
74
+ "@types/jest": "^27.5.2",
75
75
  "deepmerge": "^4.2.2",
76
76
  "jest": "^27.5.1",
77
- "ts-jest": "^27.1.4",
77
+ "ts-jest": "^27.1.5",
78
78
  "typedoc": "^0.24.8",
79
79
  "typedoc-plugin-missing-exports": "^2.0.0",
80
80
  "typescript": "~5.3.3"