@metamask/transaction-controller 52.0.0 → 52.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +52 -4
  2. package/dist/TransactionController.cjs +113 -36
  3. package/dist/TransactionController.cjs.map +1 -1
  4. package/dist/TransactionController.d.cts +38 -5
  5. package/dist/TransactionController.d.cts.map +1 -1
  6. package/dist/TransactionController.d.mts +38 -5
  7. package/dist/TransactionController.d.mts.map +1 -1
  8. package/dist/TransactionController.mjs +114 -37
  9. package/dist/TransactionController.mjs.map +1 -1
  10. package/dist/helpers/GasFeePoller.cjs +73 -1
  11. package/dist/helpers/GasFeePoller.cjs.map +1 -1
  12. package/dist/helpers/GasFeePoller.d.cts +20 -2
  13. package/dist/helpers/GasFeePoller.d.cts.map +1 -1
  14. package/dist/helpers/GasFeePoller.d.mts +20 -2
  15. package/dist/helpers/GasFeePoller.d.mts.map +1 -1
  16. package/dist/helpers/GasFeePoller.mjs +72 -1
  17. package/dist/helpers/GasFeePoller.mjs.map +1 -1
  18. package/dist/hooks/CollectPublishHook.cjs +84 -0
  19. package/dist/hooks/CollectPublishHook.cjs.map +1 -0
  20. package/dist/hooks/CollectPublishHook.d.cts +29 -0
  21. package/dist/hooks/CollectPublishHook.d.cts.map +1 -0
  22. package/dist/hooks/CollectPublishHook.d.mts +29 -0
  23. package/dist/hooks/CollectPublishHook.d.mts.map +1 -0
  24. package/dist/hooks/CollectPublishHook.mjs +80 -0
  25. package/dist/hooks/CollectPublishHook.mjs.map +1 -0
  26. package/dist/hooks/ExtraTransactionsPublishHook.cjs +90 -0
  27. package/dist/hooks/ExtraTransactionsPublishHook.cjs.map +1 -0
  28. package/dist/hooks/ExtraTransactionsPublishHook.d.cts +18 -0
  29. package/dist/hooks/ExtraTransactionsPublishHook.d.cts.map +1 -0
  30. package/dist/hooks/ExtraTransactionsPublishHook.d.mts +18 -0
  31. package/dist/hooks/ExtraTransactionsPublishHook.d.mts.map +1 -0
  32. package/dist/hooks/ExtraTransactionsPublishHook.mjs +86 -0
  33. package/dist/hooks/ExtraTransactionsPublishHook.mjs.map +1 -0
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +1 -1
  36. package/dist/index.d.cts.map +1 -1
  37. package/dist/index.d.mts +1 -1
  38. package/dist/index.d.mts.map +1 -1
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/types.cjs.map +1 -1
  41. package/dist/types.d.cts +143 -2
  42. package/dist/types.d.cts.map +1 -1
  43. package/dist/types.d.mts +143 -2
  44. package/dist/types.d.mts.map +1 -1
  45. package/dist/types.mjs.map +1 -1
  46. package/dist/utils/batch.cjs +142 -1
  47. package/dist/utils/batch.cjs.map +1 -1
  48. package/dist/utils/batch.d.cts +7 -1
  49. package/dist/utils/batch.d.cts.map +1 -1
  50. package/dist/utils/batch.d.mts +7 -1
  51. package/dist/utils/batch.d.mts.map +1 -1
  52. package/dist/utils/batch.mjs +142 -1
  53. package/dist/utils/batch.mjs.map +1 -1
  54. package/dist/utils/eip7702.cjs +12 -0
  55. package/dist/utils/eip7702.cjs.map +1 -1
  56. package/dist/utils/eip7702.d.cts.map +1 -1
  57. package/dist/utils/eip7702.d.mts.map +1 -1
  58. package/dist/utils/eip7702.mjs +12 -0
  59. package/dist/utils/eip7702.mjs.map +1 -1
  60. package/dist/utils/feature-flags.cjs +2 -2
  61. package/dist/utils/feature-flags.cjs.map +1 -1
  62. package/dist/utils/feature-flags.d.cts +2 -2
  63. package/dist/utils/feature-flags.d.mts +2 -2
  64. package/dist/utils/feature-flags.mjs +2 -2
  65. package/dist/utils/feature-flags.mjs.map +1 -1
  66. package/dist/utils/gas.cjs +115 -11
  67. package/dist/utils/gas.cjs.map +1 -1
  68. package/dist/utils/gas.d.cts +16 -5
  69. package/dist/utils/gas.d.cts.map +1 -1
  70. package/dist/utils/gas.d.mts +16 -5
  71. package/dist/utils/gas.d.mts.map +1 -1
  72. package/dist/utils/gas.mjs +115 -11
  73. package/dist/utils/gas.mjs.map +1 -1
  74. package/dist/utils/nonce.cjs +3 -3
  75. package/dist/utils/nonce.cjs.map +1 -1
  76. package/dist/utils/nonce.d.cts +2 -2
  77. package/dist/utils/nonce.d.cts.map +1 -1
  78. package/dist/utils/nonce.d.mts +2 -2
  79. package/dist/utils/nonce.d.mts.map +1 -1
  80. package/dist/utils/nonce.mjs +3 -3
  81. package/dist/utils/nonce.mjs.map +1 -1
  82. package/dist/utils/simulation-api.cjs.map +1 -1
  83. package/dist/utils/simulation-api.d.cts +46 -5
  84. package/dist/utils/simulation-api.d.cts.map +1 -1
  85. package/dist/utils/simulation-api.d.mts +46 -5
  86. package/dist/utils/simulation-api.d.mts.map +1 -1
  87. package/dist/utils/simulation-api.mjs.map +1 -1
  88. package/dist/utils/simulation.cjs +46 -7
  89. package/dist/utils/simulation.cjs.map +1 -1
  90. package/dist/utils/simulation.d.cts +6 -2
  91. package/dist/utils/simulation.d.cts.map +1 -1
  92. package/dist/utils/simulation.d.mts +6 -2
  93. package/dist/utils/simulation.d.mts.map +1 -1
  94. package/dist/utils/simulation.mjs +46 -7
  95. package/dist/utils/simulation.mjs.map +1 -1
  96. package/package.json +2 -2
@@ -8,6 +8,7 @@ const eip7702_1 = require("./eip7702.cjs");
8
8
  const feature_flags_1 = require("./feature-flags.cjs");
9
9
  const validation_1 = require("./validation.cjs");
10
10
  const __1 = require("../index.cjs");
11
+ const CollectPublishHook_1 = require("../hooks/CollectPublishHook.cjs");
11
12
  const logger_1 = require("../logger.cjs");
12
13
  const types_1 = require("../types.cjs");
13
14
  const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'batch');
@@ -25,8 +26,11 @@ async function addTransactionBatch(request) {
25
26
  request: userRequest,
26
27
  sizeLimit,
27
28
  });
28
- const { batchId: batchIdOverride, from, networkClientId, requireApproval, transactions, } = userRequest;
29
+ const { batchId: batchIdOverride, from, networkClientId, requireApproval, securityAlertId, transactions, useHook, validateSecurity, } = userRequest;
29
30
  log('Adding', userRequest);
31
+ if (useHook) {
32
+ return await addTransactionBatchWithHook(request);
33
+ }
30
34
  const chainId = getChainId(networkClientId);
31
35
  const ethQuery = request.getEthQuery(networkClientId);
32
36
  const isChainSupported = (0, eip7702_1.doesChainSupportEIP7702)(chainId, messenger);
@@ -57,13 +61,34 @@ async function addTransactionBatch(request) {
57
61
  txParams.type = types_1.TransactionEnvelopeType.setCode;
58
62
  txParams.authorizationList = [{ address: upgradeContractAddress }];
59
63
  }
64
+ if (validateSecurity) {
65
+ const securityRequest = {
66
+ method: 'eth_sendTransaction',
67
+ params: [
68
+ {
69
+ ...txParams,
70
+ authorizationList: undefined,
71
+ type: types_1.TransactionEnvelopeType.feeMarket,
72
+ },
73
+ ],
74
+ delegationMock: txParams.authorizationList?.[0]?.address,
75
+ };
76
+ log('Security request', securityRequest);
77
+ validateSecurity(securityRequest, chainId).catch((error) => {
78
+ log('Security validation failed', error);
79
+ });
80
+ }
60
81
  log('Adding batch transaction', txParams, networkClientId);
61
82
  const batchId = batchIdOverride ?? generateBatchId();
83
+ const securityAlertResponse = securityAlertId
84
+ ? { securityAlertId }
85
+ : undefined;
62
86
  const { result } = await addTransaction(txParams, {
63
87
  batchId,
64
88
  nestedTransactions,
65
89
  networkClientId,
66
90
  requireApproval,
91
+ securityAlertResponse,
67
92
  type: types_1.TransactionType.batch,
68
93
  });
69
94
  // Wait for the transaction to be published.
@@ -124,4 +149,120 @@ async function getNestedTransactionMeta(request, singleRequest, ethQuery) {
124
149
  type,
125
150
  };
126
151
  }
152
+ /**
153
+ * Process a batch transaction using a publish batch hook.
154
+ *
155
+ * @param request - The request object including the user request and necessary callbacks.
156
+ * @returns The batch result object including the batch ID.
157
+ */
158
+ async function addTransactionBatchWithHook(request) {
159
+ const { publishBatchHook, request: userRequest } = request;
160
+ const { from, networkClientId, transactions: nestedTransactions, } = userRequest;
161
+ log('Adding transaction batch using hook', userRequest);
162
+ if (!publishBatchHook) {
163
+ log('No publish batch hook provided');
164
+ throw new Error('No publish batch hook provided');
165
+ }
166
+ const batchId = generateBatchId();
167
+ const transactionCount = nestedTransactions.length;
168
+ const collectHook = new CollectPublishHook_1.CollectPublishHook(transactionCount);
169
+ const publishHook = collectHook.getHook();
170
+ const hookTransactions = [];
171
+ try {
172
+ for (const nestedTransaction of nestedTransactions) {
173
+ const hookTransaction = await processTransactionWithHook(batchId, nestedTransaction, publishHook, request);
174
+ hookTransactions.push(hookTransaction);
175
+ }
176
+ const { signedTransactions } = await collectHook.ready();
177
+ const transactions = hookTransactions.map((transaction, index) => ({
178
+ ...transaction,
179
+ signedTx: signedTransactions[index],
180
+ }));
181
+ log('Calling publish batch hook', { from, networkClientId, transactions });
182
+ const result = await publishBatchHook({
183
+ from,
184
+ networkClientId,
185
+ transactions,
186
+ });
187
+ log('Publish batch hook result', result);
188
+ if (!result) {
189
+ throw new Error('Publish batch hook did not return a result');
190
+ }
191
+ const transactionHashes = result.results.map(({ transactionHash }) => transactionHash);
192
+ collectHook.success(transactionHashes);
193
+ log('Completed batch transaction with hook', transactionHashes);
194
+ return {
195
+ batchId,
196
+ };
197
+ }
198
+ catch (error) {
199
+ log('Publish batch hook failed', error);
200
+ collectHook.error(error);
201
+ throw error;
202
+ }
203
+ }
204
+ /**
205
+ * Process a single transaction with a publish batch hook.
206
+ *
207
+ * @param batchId - ID of the transaction batch.
208
+ * @param nestedTransaction - The nested transaction request.
209
+ * @param publishHook - The publish hook to use for each transaction.
210
+ * @param request - The request object including the user request and necessary callbacks.
211
+ * @returns The single transaction request to be processed by the publish batch hook.
212
+ */
213
+ async function processTransactionWithHook(batchId, nestedTransaction, publishHook, request) {
214
+ const { existingTransaction, params } = nestedTransaction;
215
+ const { addTransaction, getTransaction, request: userRequest, updateTransaction, } = request;
216
+ const { from, networkClientId } = userRequest;
217
+ if (existingTransaction) {
218
+ const { id, onPublish, signedTransaction } = existingTransaction;
219
+ const transactionMeta = getTransaction(id);
220
+ updateTransaction({ transactionId: id }, (_transactionMeta) => {
221
+ _transactionMeta.batchId = batchId;
222
+ });
223
+ publishHook(transactionMeta, signedTransaction)
224
+ .then(onPublish)
225
+ .catch(() => {
226
+ // Intentionally empty
227
+ });
228
+ log('Processed existing transaction with hook', {
229
+ id,
230
+ params,
231
+ });
232
+ return {
233
+ id,
234
+ params,
235
+ };
236
+ }
237
+ const { transactionMeta } = await addTransaction({
238
+ ...params,
239
+ from,
240
+ }, {
241
+ batchId,
242
+ disableGasBuffer: true,
243
+ networkClientId,
244
+ publishHook,
245
+ requireApproval: false,
246
+ });
247
+ const { id, txParams } = transactionMeta;
248
+ const data = txParams.data;
249
+ const gas = txParams.gas;
250
+ const maxFeePerGas = txParams.maxFeePerGas;
251
+ const maxPriorityFeePerGas = txParams.maxPriorityFeePerGas;
252
+ const to = txParams.to;
253
+ const value = txParams.value;
254
+ const newParams = {
255
+ data,
256
+ gas,
257
+ maxFeePerGas,
258
+ maxPriorityFeePerGas,
259
+ to,
260
+ value,
261
+ };
262
+ log('Processed new transaction with hook', { id, params: newParams });
263
+ return {
264
+ id,
265
+ params: newParams,
266
+ };
267
+ }
127
268
  //# sourceMappingURL=batch.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"batch.cjs","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { bytesToHex, createModuleLogger } from '@metamask/utils';\nimport { parse, v4 } from 'uuid';\n\nimport {\n doesChainSupportEIP7702,\n generateEIP7702BatchTransaction,\n isAccountUpgradedToEIP7702,\n} from './eip7702';\nimport {\n getBatchSizeLimit,\n getEIP7702SupportedChains,\n getEIP7702UpgradeContractAddress,\n} from './feature-flags';\nimport { validateBatchRequest } from './validation';\nimport {\n determineTransactionType,\n type TransactionBatchRequest,\n type TransactionController,\n type TransactionControllerMessenger,\n} from '..';\nimport { projectLogger } from '../logger';\nimport type {\n NestedTransactionMetadata,\n TransactionBatchSingleRequest,\n} from '../types';\nimport {\n TransactionEnvelopeType,\n type TransactionBatchResult,\n type TransactionParams,\n TransactionType,\n} from '../types';\n\ntype AddTransactionBatchRequest = {\n addTransaction: TransactionController['addTransaction'];\n getChainId: (networkClientId: string) => Hex;\n getEthQuery: (networkClientId: string) => EthQuery;\n getInternalAccounts: () => Hex[];\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n request: TransactionBatchRequest;\n};\n\ntype IsAtomicBatchSupportedRequest = {\n address: Hex;\n getEthQuery: (chainId: Hex) => EthQuery;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n};\n\nconst log = createModuleLogger(projectLogger, 'batch');\n\n/**\n * Add a batch transaction.\n *\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The batch result object including the batch ID.\n */\nexport async function addTransactionBatch(\n request: AddTransactionBatchRequest,\n): Promise<TransactionBatchResult> {\n const {\n addTransaction,\n getChainId,\n getInternalAccounts,\n messenger,\n publicKeyEIP7702,\n request: userRequest,\n } = request;\n\n const sizeLimit = getBatchSizeLimit(messenger);\n\n validateBatchRequest({\n internalAccounts: getInternalAccounts(),\n request: userRequest,\n sizeLimit,\n });\n\n const {\n batchId: batchIdOverride,\n from,\n networkClientId,\n requireApproval,\n transactions,\n } = userRequest;\n\n log('Adding', userRequest);\n\n const chainId = getChainId(networkClientId);\n const ethQuery = request.getEthQuery(networkClientId);\n const isChainSupported = doesChainSupportEIP7702(chainId, messenger);\n\n if (!isChainSupported) {\n log('Chain does not support EIP-7702', chainId);\n throw rpcErrors.internal('Chain does not support EIP-7702');\n }\n\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const { delegationAddress, isSupported } = await isAccountUpgradedToEIP7702(\n from,\n chainId,\n publicKeyEIP7702,\n messenger,\n ethQuery,\n );\n\n log('Account', { delegationAddress, isSupported });\n\n if (!isSupported && delegationAddress) {\n log('Account upgraded to unsupported contract', from, delegationAddress);\n throw rpcErrors.internal('Account upgraded to unsupported contract');\n }\n\n const nestedTransactions = await Promise.all(\n transactions.map((tx) =>\n getNestedTransactionMeta(userRequest, tx, ethQuery),\n ),\n );\n\n const batchParams = generateEIP7702BatchTransaction(from, nestedTransactions);\n\n const txParams: TransactionParams = {\n from,\n ...batchParams,\n };\n\n if (!isSupported) {\n const upgradeContractAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeContractAddress) {\n throw rpcErrors.internal('Upgrade contract address not found');\n }\n\n txParams.type = TransactionEnvelopeType.setCode;\n txParams.authorizationList = [{ address: upgradeContractAddress }];\n }\n\n log('Adding batch transaction', txParams, networkClientId);\n\n const batchId = batchIdOverride ?? generateBatchId();\n\n const { result } = await addTransaction(txParams, {\n batchId,\n nestedTransactions,\n networkClientId,\n requireApproval,\n type: TransactionType.batch,\n });\n\n // Wait for the transaction to be published.\n await result;\n\n return {\n batchId,\n };\n}\n\n/**\n * Determine which chains support atomic batch transactions for the given account.\n *\n * @param request - The request object including the account address and necessary callbacks.\n * @returns The chain IDs that support atomic batch transactions.\n */\nexport async function isAtomicBatchSupported(\n request: IsAtomicBatchSupportedRequest,\n): Promise<Hex[]> {\n const {\n address,\n getEthQuery,\n messenger,\n publicKeyEIP7702: publicKey,\n } = request;\n\n if (!publicKey) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const chainIds7702 = getEIP7702SupportedChains(messenger);\n const chainIds: Hex[] = [];\n\n for (const chainId of chainIds7702) {\n const ethQuery = getEthQuery(chainId);\n\n const { isSupported, delegationAddress } = await isAccountUpgradedToEIP7702(\n address,\n chainId,\n publicKey,\n messenger,\n ethQuery,\n );\n\n if (!delegationAddress || isSupported) {\n chainIds.push(chainId);\n }\n }\n\n log('Atomic batch supported chains', chainIds);\n\n return chainIds;\n}\n\n/**\n * Generate a tranasction batch ID.\n *\n * @returns A unique batch ID as a hexadecimal string.\n */\nfunction generateBatchId(): Hex {\n const idString = v4();\n const idBytes = new Uint8Array(parse(idString));\n return bytesToHex(idBytes);\n}\n\n/**\n * Generate the metadata for a nested transaction.\n *\n * @param request - The batch request.\n * @param singleRequest - The request for a single transaction.\n * @param ethQuery - The EthQuery instance used to interact with the Ethereum blockchain.\n * @returns The metadata for the nested transaction.\n */\nasync function getNestedTransactionMeta(\n request: TransactionBatchRequest,\n singleRequest: TransactionBatchSingleRequest,\n ethQuery: EthQuery,\n): Promise<NestedTransactionMetadata> {\n const { from } = request;\n const { params } = singleRequest;\n\n const { type } = await determineTransactionType(\n { from, ...params },\n ethQuery,\n );\n\n return {\n ...params,\n type,\n };\n}\n"]}
1
+ {"version":3,"file":"batch.cjs","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { bytesToHex, createModuleLogger } from '@metamask/utils';\nimport { parse, v4 } from 'uuid';\n\nimport {\n doesChainSupportEIP7702,\n generateEIP7702BatchTransaction,\n isAccountUpgradedToEIP7702,\n} from './eip7702';\nimport {\n getBatchSizeLimit,\n getEIP7702SupportedChains,\n getEIP7702UpgradeContractAddress,\n} from './feature-flags';\nimport { validateBatchRequest } from './validation';\nimport {\n determineTransactionType,\n type BatchTransactionParams,\n type TransactionController,\n type TransactionControllerMessenger,\n type TransactionMeta,\n} from '..';\nimport { CollectPublishHook } from '../hooks/CollectPublishHook';\nimport { projectLogger } from '../logger';\nimport type {\n NestedTransactionMetadata,\n SecurityAlertResponse,\n TransactionBatchSingleRequest,\n PublishBatchHook,\n PublishBatchHookTransaction,\n PublishHook,\n TransactionBatchRequest,\n ValidateSecurityRequest,\n} from '../types';\nimport {\n TransactionEnvelopeType,\n type TransactionBatchResult,\n type TransactionParams,\n TransactionType,\n} from '../types';\n\ntype AddTransactionBatchRequest = {\n addTransaction: TransactionController['addTransaction'];\n getChainId: (networkClientId: string) => Hex;\n getEthQuery: (networkClientId: string) => EthQuery;\n getInternalAccounts: () => Hex[];\n getTransaction: (id: string) => TransactionMeta;\n messenger: TransactionControllerMessenger;\n publishBatchHook?: PublishBatchHook;\n publicKeyEIP7702?: Hex;\n request: TransactionBatchRequest;\n updateTransaction: (\n options: { transactionId: string },\n callback: (transactionMeta: TransactionMeta) => void,\n ) => void;\n};\n\ntype IsAtomicBatchSupportedRequest = {\n address: Hex;\n getEthQuery: (chainId: Hex) => EthQuery;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n};\n\nconst log = createModuleLogger(projectLogger, 'batch');\n\n/**\n * Add a batch transaction.\n *\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The batch result object including the batch ID.\n */\nexport async function addTransactionBatch(\n request: AddTransactionBatchRequest,\n): Promise<TransactionBatchResult> {\n const {\n addTransaction,\n getChainId,\n getInternalAccounts,\n messenger,\n publicKeyEIP7702,\n request: userRequest,\n } = request;\n\n const sizeLimit = getBatchSizeLimit(messenger);\n\n validateBatchRequest({\n internalAccounts: getInternalAccounts(),\n request: userRequest,\n sizeLimit,\n });\n\n const {\n batchId: batchIdOverride,\n from,\n networkClientId,\n requireApproval,\n securityAlertId,\n transactions,\n useHook,\n validateSecurity,\n } = userRequest;\n\n log('Adding', userRequest);\n\n if (useHook) {\n return await addTransactionBatchWithHook(request);\n }\n\n const chainId = getChainId(networkClientId);\n const ethQuery = request.getEthQuery(networkClientId);\n const isChainSupported = doesChainSupportEIP7702(chainId, messenger);\n\n if (!isChainSupported) {\n log('Chain does not support EIP-7702', chainId);\n throw rpcErrors.internal('Chain does not support EIP-7702');\n }\n\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const { delegationAddress, isSupported } = await isAccountUpgradedToEIP7702(\n from,\n chainId,\n publicKeyEIP7702,\n messenger,\n ethQuery,\n );\n\n log('Account', { delegationAddress, isSupported });\n\n if (!isSupported && delegationAddress) {\n log('Account upgraded to unsupported contract', from, delegationAddress);\n throw rpcErrors.internal('Account upgraded to unsupported contract');\n }\n\n const nestedTransactions = await Promise.all(\n transactions.map((tx) =>\n getNestedTransactionMeta(userRequest, tx, ethQuery),\n ),\n );\n\n const batchParams = generateEIP7702BatchTransaction(from, nestedTransactions);\n\n const txParams: TransactionParams = {\n from,\n ...batchParams,\n };\n\n if (!isSupported) {\n const upgradeContractAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeContractAddress) {\n throw rpcErrors.internal('Upgrade contract address not found');\n }\n\n txParams.type = TransactionEnvelopeType.setCode;\n txParams.authorizationList = [{ address: upgradeContractAddress }];\n }\n\n if (validateSecurity) {\n const securityRequest: ValidateSecurityRequest = {\n method: 'eth_sendTransaction',\n params: [\n {\n ...txParams,\n authorizationList: undefined,\n type: TransactionEnvelopeType.feeMarket,\n },\n ],\n delegationMock: txParams.authorizationList?.[0]?.address,\n };\n\n log('Security request', securityRequest);\n\n validateSecurity(securityRequest, chainId).catch((error) => {\n log('Security validation failed', error);\n });\n }\n\n log('Adding batch transaction', txParams, networkClientId);\n\n const batchId = batchIdOverride ?? generateBatchId();\n\n const securityAlertResponse = securityAlertId\n ? ({ securityAlertId } as SecurityAlertResponse)\n : undefined;\n\n const { result } = await addTransaction(txParams, {\n batchId,\n nestedTransactions,\n networkClientId,\n requireApproval,\n securityAlertResponse,\n type: TransactionType.batch,\n });\n\n // Wait for the transaction to be published.\n await result;\n\n return {\n batchId,\n };\n}\n\n/**\n * Determine which chains support atomic batch transactions for the given account.\n *\n * @param request - The request object including the account address and necessary callbacks.\n * @returns The chain IDs that support atomic batch transactions.\n */\nexport async function isAtomicBatchSupported(\n request: IsAtomicBatchSupportedRequest,\n): Promise<Hex[]> {\n const {\n address,\n getEthQuery,\n messenger,\n publicKeyEIP7702: publicKey,\n } = request;\n\n if (!publicKey) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const chainIds7702 = getEIP7702SupportedChains(messenger);\n const chainIds: Hex[] = [];\n\n for (const chainId of chainIds7702) {\n const ethQuery = getEthQuery(chainId);\n\n const { isSupported, delegationAddress } = await isAccountUpgradedToEIP7702(\n address,\n chainId,\n publicKey,\n messenger,\n ethQuery,\n );\n\n if (!delegationAddress || isSupported) {\n chainIds.push(chainId);\n }\n }\n\n log('Atomic batch supported chains', chainIds);\n\n return chainIds;\n}\n\n/**\n * Generate a tranasction batch ID.\n *\n * @returns A unique batch ID as a hexadecimal string.\n */\nfunction generateBatchId(): Hex {\n const idString = v4();\n const idBytes = new Uint8Array(parse(idString));\n return bytesToHex(idBytes);\n}\n\n/**\n * Generate the metadata for a nested transaction.\n *\n * @param request - The batch request.\n * @param singleRequest - The request for a single transaction.\n * @param ethQuery - The EthQuery instance used to interact with the Ethereum blockchain.\n * @returns The metadata for the nested transaction.\n */\nasync function getNestedTransactionMeta(\n request: TransactionBatchRequest,\n singleRequest: TransactionBatchSingleRequest,\n ethQuery: EthQuery,\n): Promise<NestedTransactionMetadata> {\n const { from } = request;\n const { params } = singleRequest;\n\n const { type } = await determineTransactionType(\n { from, ...params },\n ethQuery,\n );\n\n return {\n ...params,\n type,\n };\n}\n\n/**\n * Process a batch transaction using a publish batch hook.\n *\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The batch result object including the batch ID.\n */\nasync function addTransactionBatchWithHook(\n request: AddTransactionBatchRequest,\n): Promise<TransactionBatchResult> {\n const { publishBatchHook, request: userRequest } = request;\n\n const {\n from,\n networkClientId,\n transactions: nestedTransactions,\n } = userRequest;\n\n log('Adding transaction batch using hook', userRequest);\n\n if (!publishBatchHook) {\n log('No publish batch hook provided');\n throw new Error('No publish batch hook provided');\n }\n\n const batchId = generateBatchId();\n const transactionCount = nestedTransactions.length;\n const collectHook = new CollectPublishHook(transactionCount);\n const publishHook = collectHook.getHook();\n const hookTransactions: Omit<PublishBatchHookTransaction, 'signedTx'>[] = [];\n\n try {\n for (const nestedTransaction of nestedTransactions) {\n const hookTransaction = await processTransactionWithHook(\n batchId,\n nestedTransaction,\n publishHook,\n request,\n );\n\n hookTransactions.push(hookTransaction);\n }\n\n const { signedTransactions } = await collectHook.ready();\n\n const transactions = hookTransactions.map((transaction, index) => ({\n ...transaction,\n signedTx: signedTransactions[index],\n }));\n\n log('Calling publish batch hook', { from, networkClientId, transactions });\n\n const result = await publishBatchHook({\n from,\n networkClientId,\n transactions,\n });\n\n log('Publish batch hook result', result);\n\n if (!result) {\n throw new Error('Publish batch hook did not return a result');\n }\n\n const transactionHashes = result.results.map(\n ({ transactionHash }) => transactionHash,\n );\n\n collectHook.success(transactionHashes);\n\n log('Completed batch transaction with hook', transactionHashes);\n\n return {\n batchId,\n };\n } catch (error) {\n log('Publish batch hook failed', error);\n\n collectHook.error(error);\n\n throw error;\n }\n}\n\n/**\n * Process a single transaction with a publish batch hook.\n *\n * @param batchId - ID of the transaction batch.\n * @param nestedTransaction - The nested transaction request.\n * @param publishHook - The publish hook to use for each transaction.\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The single transaction request to be processed by the publish batch hook.\n */\nasync function processTransactionWithHook(\n batchId: Hex,\n nestedTransaction: TransactionBatchSingleRequest,\n publishHook: PublishHook,\n request: AddTransactionBatchRequest,\n) {\n const { existingTransaction, params } = nestedTransaction;\n\n const {\n addTransaction,\n getTransaction,\n request: userRequest,\n updateTransaction,\n } = request;\n\n const { from, networkClientId } = userRequest;\n\n if (existingTransaction) {\n const { id, onPublish, signedTransaction } = existingTransaction;\n const transactionMeta = getTransaction(id);\n\n updateTransaction({ transactionId: id }, (_transactionMeta) => {\n _transactionMeta.batchId = batchId;\n });\n\n publishHook(transactionMeta, signedTransaction)\n .then(onPublish)\n .catch(() => {\n // Intentionally empty\n });\n\n log('Processed existing transaction with hook', {\n id,\n params,\n });\n\n return {\n id,\n params,\n };\n }\n\n const { transactionMeta } = await addTransaction(\n {\n ...params,\n from,\n },\n {\n batchId,\n disableGasBuffer: true,\n networkClientId,\n publishHook,\n requireApproval: false,\n },\n );\n\n const { id, txParams } = transactionMeta;\n const data = txParams.data as Hex | undefined;\n const gas = txParams.gas as Hex | undefined;\n const maxFeePerGas = txParams.maxFeePerGas as Hex | undefined;\n const maxPriorityFeePerGas = txParams.maxPriorityFeePerGas as Hex | undefined;\n const to = txParams.to as Hex | undefined;\n const value = txParams.value as Hex | undefined;\n\n const newParams: BatchTransactionParams = {\n data,\n gas,\n maxFeePerGas,\n maxPriorityFeePerGas,\n to,\n value,\n };\n\n log('Processed new transaction with hook', { id, params: newParams });\n\n return {\n id,\n params: newParams,\n };\n}\n"]}
@@ -1,15 +1,21 @@
1
1
  import type EthQuery from "@metamask/eth-query";
2
2
  import type { Hex } from "@metamask/utils";
3
- import { type TransactionBatchRequest, type TransactionController, type TransactionControllerMessenger } from "../index.cjs";
3
+ import { type TransactionController, type TransactionControllerMessenger, type TransactionMeta } from "../index.cjs";
4
+ import type { PublishBatchHook, TransactionBatchRequest } from "../types.cjs";
4
5
  import { type TransactionBatchResult } from "../types.cjs";
5
6
  type AddTransactionBatchRequest = {
6
7
  addTransaction: TransactionController['addTransaction'];
7
8
  getChainId: (networkClientId: string) => Hex;
8
9
  getEthQuery: (networkClientId: string) => EthQuery;
9
10
  getInternalAccounts: () => Hex[];
11
+ getTransaction: (id: string) => TransactionMeta;
10
12
  messenger: TransactionControllerMessenger;
13
+ publishBatchHook?: PublishBatchHook;
11
14
  publicKeyEIP7702?: Hex;
12
15
  request: TransactionBatchRequest;
16
+ updateTransaction: (options: {
17
+ transactionId: string;
18
+ }, callback: (transactionMeta: TransactionMeta) => void) => void;
13
19
  };
14
20
  type IsAtomicBatchSupportedRequest = {
15
21
  address: Hex;
@@ -1 +1 @@
1
- {"version":3,"file":"batch.d.cts","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAe3C,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACpC,qBAAW;AAMZ,OAAO,EAEL,KAAK,sBAAsB,EAG5B,qBAAiB;AAElB,KAAK,0BAA0B,GAAG;IAChC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IACxD,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,WAAW,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,QAAQ,CAAC;IACnD,mBAAmB,EAAE,MAAM,GAAG,EAAE,CAAC;IACjC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,OAAO,EAAE,uBAAuB,CAAC;CAClC,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAsGjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,GAAG,EAAE,CAAC,CAkChB"}
1
+ {"version":3,"file":"batch.d.cts","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAe3C,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,eAAe,EACrB,qBAAW;AAGZ,OAAO,KAAK,EAIV,gBAAgB,EAGhB,uBAAuB,EAExB,qBAAiB;AAClB,OAAO,EAEL,KAAK,sBAAsB,EAG5B,qBAAiB;AAElB,KAAK,0BAA0B,GAAG;IAChC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IACxD,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,WAAW,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,QAAQ,CAAC;IACnD,mBAAmB,EAAE,MAAM,GAAG,EAAE,CAAC;IACjC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,eAAe,CAAC;IAChD,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,OAAO,EAAE,uBAAuB,CAAC;IACjC,iBAAiB,EAAE,CACjB,OAAO,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,EAClC,QAAQ,EAAE,CAAC,eAAe,EAAE,eAAe,KAAK,IAAI,KACjD,IAAI,CAAC;CACX,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAsIjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,GAAG,EAAE,CAAC,CAkChB"}
@@ -1,15 +1,21 @@
1
1
  import type EthQuery from "@metamask/eth-query";
2
2
  import type { Hex } from "@metamask/utils";
3
- import { type TransactionBatchRequest, type TransactionController, type TransactionControllerMessenger } from "../index.mjs";
3
+ import { type TransactionController, type TransactionControllerMessenger, type TransactionMeta } from "../index.mjs";
4
+ import type { PublishBatchHook, TransactionBatchRequest } from "../types.mjs";
4
5
  import { type TransactionBatchResult } from "../types.mjs";
5
6
  type AddTransactionBatchRequest = {
6
7
  addTransaction: TransactionController['addTransaction'];
7
8
  getChainId: (networkClientId: string) => Hex;
8
9
  getEthQuery: (networkClientId: string) => EthQuery;
9
10
  getInternalAccounts: () => Hex[];
11
+ getTransaction: (id: string) => TransactionMeta;
10
12
  messenger: TransactionControllerMessenger;
13
+ publishBatchHook?: PublishBatchHook;
11
14
  publicKeyEIP7702?: Hex;
12
15
  request: TransactionBatchRequest;
16
+ updateTransaction: (options: {
17
+ transactionId: string;
18
+ }, callback: (transactionMeta: TransactionMeta) => void) => void;
13
19
  };
14
20
  type IsAtomicBatchSupportedRequest = {
15
21
  address: Hex;
@@ -1 +1 @@
1
- {"version":3,"file":"batch.d.mts","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAe3C,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACpC,qBAAW;AAMZ,OAAO,EAEL,KAAK,sBAAsB,EAG5B,qBAAiB;AAElB,KAAK,0BAA0B,GAAG;IAChC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IACxD,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,WAAW,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,QAAQ,CAAC;IACnD,mBAAmB,EAAE,MAAM,GAAG,EAAE,CAAC;IACjC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,OAAO,EAAE,uBAAuB,CAAC;CAClC,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAsGjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,GAAG,EAAE,CAAC,CAkChB"}
1
+ {"version":3,"file":"batch.d.mts","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAe3C,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,eAAe,EACrB,qBAAW;AAGZ,OAAO,KAAK,EAIV,gBAAgB,EAGhB,uBAAuB,EAExB,qBAAiB;AAClB,OAAO,EAEL,KAAK,sBAAsB,EAG5B,qBAAiB;AAElB,KAAK,0BAA0B,GAAG;IAChC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IACxD,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,WAAW,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,QAAQ,CAAC;IACnD,mBAAmB,EAAE,MAAM,GAAG,EAAE,CAAC;IACjC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,eAAe,CAAC;IAChD,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,OAAO,EAAE,uBAAuB,CAAC;IACjC,iBAAiB,EAAE,CACjB,OAAO,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,EAClC,QAAQ,EAAE,CAAC,eAAe,EAAE,eAAe,KAAK,IAAI,KACjD,IAAI,CAAC;CACX,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAsIjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,GAAG,EAAE,CAAC,CAkChB"}
@@ -5,6 +5,7 @@ import { doesChainSupportEIP7702, generateEIP7702BatchTransaction, isAccountUpgr
5
5
  import { getBatchSizeLimit, getEIP7702SupportedChains, getEIP7702UpgradeContractAddress } from "./feature-flags.mjs";
6
6
  import { validateBatchRequest } from "./validation.mjs";
7
7
  import { determineTransactionType } from "../index.mjs";
8
+ import { CollectPublishHook } from "../hooks/CollectPublishHook.mjs";
8
9
  import { projectLogger } from "../logger.mjs";
9
10
  import { TransactionEnvelopeType, TransactionType } from "../types.mjs";
10
11
  const log = createModuleLogger(projectLogger, 'batch');
@@ -22,8 +23,11 @@ export async function addTransactionBatch(request) {
22
23
  request: userRequest,
23
24
  sizeLimit,
24
25
  });
25
- const { batchId: batchIdOverride, from, networkClientId, requireApproval, transactions, } = userRequest;
26
+ const { batchId: batchIdOverride, from, networkClientId, requireApproval, securityAlertId, transactions, useHook, validateSecurity, } = userRequest;
26
27
  log('Adding', userRequest);
28
+ if (useHook) {
29
+ return await addTransactionBatchWithHook(request);
30
+ }
27
31
  const chainId = getChainId(networkClientId);
28
32
  const ethQuery = request.getEthQuery(networkClientId);
29
33
  const isChainSupported = doesChainSupportEIP7702(chainId, messenger);
@@ -54,13 +58,34 @@ export async function addTransactionBatch(request) {
54
58
  txParams.type = TransactionEnvelopeType.setCode;
55
59
  txParams.authorizationList = [{ address: upgradeContractAddress }];
56
60
  }
61
+ if (validateSecurity) {
62
+ const securityRequest = {
63
+ method: 'eth_sendTransaction',
64
+ params: [
65
+ {
66
+ ...txParams,
67
+ authorizationList: undefined,
68
+ type: TransactionEnvelopeType.feeMarket,
69
+ },
70
+ ],
71
+ delegationMock: txParams.authorizationList?.[0]?.address,
72
+ };
73
+ log('Security request', securityRequest);
74
+ validateSecurity(securityRequest, chainId).catch((error) => {
75
+ log('Security validation failed', error);
76
+ });
77
+ }
57
78
  log('Adding batch transaction', txParams, networkClientId);
58
79
  const batchId = batchIdOverride ?? generateBatchId();
80
+ const securityAlertResponse = securityAlertId
81
+ ? { securityAlertId }
82
+ : undefined;
59
83
  const { result } = await addTransaction(txParams, {
60
84
  batchId,
61
85
  nestedTransactions,
62
86
  networkClientId,
63
87
  requireApproval,
88
+ securityAlertResponse,
64
89
  type: TransactionType.batch,
65
90
  });
66
91
  // Wait for the transaction to be published.
@@ -119,4 +144,120 @@ async function getNestedTransactionMeta(request, singleRequest, ethQuery) {
119
144
  type,
120
145
  };
121
146
  }
147
+ /**
148
+ * Process a batch transaction using a publish batch hook.
149
+ *
150
+ * @param request - The request object including the user request and necessary callbacks.
151
+ * @returns The batch result object including the batch ID.
152
+ */
153
+ async function addTransactionBatchWithHook(request) {
154
+ const { publishBatchHook, request: userRequest } = request;
155
+ const { from, networkClientId, transactions: nestedTransactions, } = userRequest;
156
+ log('Adding transaction batch using hook', userRequest);
157
+ if (!publishBatchHook) {
158
+ log('No publish batch hook provided');
159
+ throw new Error('No publish batch hook provided');
160
+ }
161
+ const batchId = generateBatchId();
162
+ const transactionCount = nestedTransactions.length;
163
+ const collectHook = new CollectPublishHook(transactionCount);
164
+ const publishHook = collectHook.getHook();
165
+ const hookTransactions = [];
166
+ try {
167
+ for (const nestedTransaction of nestedTransactions) {
168
+ const hookTransaction = await processTransactionWithHook(batchId, nestedTransaction, publishHook, request);
169
+ hookTransactions.push(hookTransaction);
170
+ }
171
+ const { signedTransactions } = await collectHook.ready();
172
+ const transactions = hookTransactions.map((transaction, index) => ({
173
+ ...transaction,
174
+ signedTx: signedTransactions[index],
175
+ }));
176
+ log('Calling publish batch hook', { from, networkClientId, transactions });
177
+ const result = await publishBatchHook({
178
+ from,
179
+ networkClientId,
180
+ transactions,
181
+ });
182
+ log('Publish batch hook result', result);
183
+ if (!result) {
184
+ throw new Error('Publish batch hook did not return a result');
185
+ }
186
+ const transactionHashes = result.results.map(({ transactionHash }) => transactionHash);
187
+ collectHook.success(transactionHashes);
188
+ log('Completed batch transaction with hook', transactionHashes);
189
+ return {
190
+ batchId,
191
+ };
192
+ }
193
+ catch (error) {
194
+ log('Publish batch hook failed', error);
195
+ collectHook.error(error);
196
+ throw error;
197
+ }
198
+ }
199
+ /**
200
+ * Process a single transaction with a publish batch hook.
201
+ *
202
+ * @param batchId - ID of the transaction batch.
203
+ * @param nestedTransaction - The nested transaction request.
204
+ * @param publishHook - The publish hook to use for each transaction.
205
+ * @param request - The request object including the user request and necessary callbacks.
206
+ * @returns The single transaction request to be processed by the publish batch hook.
207
+ */
208
+ async function processTransactionWithHook(batchId, nestedTransaction, publishHook, request) {
209
+ const { existingTransaction, params } = nestedTransaction;
210
+ const { addTransaction, getTransaction, request: userRequest, updateTransaction, } = request;
211
+ const { from, networkClientId } = userRequest;
212
+ if (existingTransaction) {
213
+ const { id, onPublish, signedTransaction } = existingTransaction;
214
+ const transactionMeta = getTransaction(id);
215
+ updateTransaction({ transactionId: id }, (_transactionMeta) => {
216
+ _transactionMeta.batchId = batchId;
217
+ });
218
+ publishHook(transactionMeta, signedTransaction)
219
+ .then(onPublish)
220
+ .catch(() => {
221
+ // Intentionally empty
222
+ });
223
+ log('Processed existing transaction with hook', {
224
+ id,
225
+ params,
226
+ });
227
+ return {
228
+ id,
229
+ params,
230
+ };
231
+ }
232
+ const { transactionMeta } = await addTransaction({
233
+ ...params,
234
+ from,
235
+ }, {
236
+ batchId,
237
+ disableGasBuffer: true,
238
+ networkClientId,
239
+ publishHook,
240
+ requireApproval: false,
241
+ });
242
+ const { id, txParams } = transactionMeta;
243
+ const data = txParams.data;
244
+ const gas = txParams.gas;
245
+ const maxFeePerGas = txParams.maxFeePerGas;
246
+ const maxPriorityFeePerGas = txParams.maxPriorityFeePerGas;
247
+ const to = txParams.to;
248
+ const value = txParams.value;
249
+ const newParams = {
250
+ data,
251
+ gas,
252
+ maxFeePerGas,
253
+ maxPriorityFeePerGas,
254
+ to,
255
+ value,
256
+ };
257
+ log('Processed new transaction with hook', { id, params: newParams });
258
+ return {
259
+ id,
260
+ params: newParams,
261
+ };
262
+ }
122
263
  //# sourceMappingURL=batch.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"batch.mjs","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { bytesToHex, createModuleLogger } from '@metamask/utils';\nimport { parse, v4 } from 'uuid';\n\nimport {\n doesChainSupportEIP7702,\n generateEIP7702BatchTransaction,\n isAccountUpgradedToEIP7702,\n} from './eip7702';\nimport {\n getBatchSizeLimit,\n getEIP7702SupportedChains,\n getEIP7702UpgradeContractAddress,\n} from './feature-flags';\nimport { validateBatchRequest } from './validation';\nimport {\n determineTransactionType,\n type TransactionBatchRequest,\n type TransactionController,\n type TransactionControllerMessenger,\n} from '..';\nimport { projectLogger } from '../logger';\nimport type {\n NestedTransactionMetadata,\n TransactionBatchSingleRequest,\n} from '../types';\nimport {\n TransactionEnvelopeType,\n type TransactionBatchResult,\n type TransactionParams,\n TransactionType,\n} from '../types';\n\ntype AddTransactionBatchRequest = {\n addTransaction: TransactionController['addTransaction'];\n getChainId: (networkClientId: string) => Hex;\n getEthQuery: (networkClientId: string) => EthQuery;\n getInternalAccounts: () => Hex[];\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n request: TransactionBatchRequest;\n};\n\ntype IsAtomicBatchSupportedRequest = {\n address: Hex;\n getEthQuery: (chainId: Hex) => EthQuery;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n};\n\nconst log = createModuleLogger(projectLogger, 'batch');\n\n/**\n * Add a batch transaction.\n *\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The batch result object including the batch ID.\n */\nexport async function addTransactionBatch(\n request: AddTransactionBatchRequest,\n): Promise<TransactionBatchResult> {\n const {\n addTransaction,\n getChainId,\n getInternalAccounts,\n messenger,\n publicKeyEIP7702,\n request: userRequest,\n } = request;\n\n const sizeLimit = getBatchSizeLimit(messenger);\n\n validateBatchRequest({\n internalAccounts: getInternalAccounts(),\n request: userRequest,\n sizeLimit,\n });\n\n const {\n batchId: batchIdOverride,\n from,\n networkClientId,\n requireApproval,\n transactions,\n } = userRequest;\n\n log('Adding', userRequest);\n\n const chainId = getChainId(networkClientId);\n const ethQuery = request.getEthQuery(networkClientId);\n const isChainSupported = doesChainSupportEIP7702(chainId, messenger);\n\n if (!isChainSupported) {\n log('Chain does not support EIP-7702', chainId);\n throw rpcErrors.internal('Chain does not support EIP-7702');\n }\n\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const { delegationAddress, isSupported } = await isAccountUpgradedToEIP7702(\n from,\n chainId,\n publicKeyEIP7702,\n messenger,\n ethQuery,\n );\n\n log('Account', { delegationAddress, isSupported });\n\n if (!isSupported && delegationAddress) {\n log('Account upgraded to unsupported contract', from, delegationAddress);\n throw rpcErrors.internal('Account upgraded to unsupported contract');\n }\n\n const nestedTransactions = await Promise.all(\n transactions.map((tx) =>\n getNestedTransactionMeta(userRequest, tx, ethQuery),\n ),\n );\n\n const batchParams = generateEIP7702BatchTransaction(from, nestedTransactions);\n\n const txParams: TransactionParams = {\n from,\n ...batchParams,\n };\n\n if (!isSupported) {\n const upgradeContractAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeContractAddress) {\n throw rpcErrors.internal('Upgrade contract address not found');\n }\n\n txParams.type = TransactionEnvelopeType.setCode;\n txParams.authorizationList = [{ address: upgradeContractAddress }];\n }\n\n log('Adding batch transaction', txParams, networkClientId);\n\n const batchId = batchIdOverride ?? generateBatchId();\n\n const { result } = await addTransaction(txParams, {\n batchId,\n nestedTransactions,\n networkClientId,\n requireApproval,\n type: TransactionType.batch,\n });\n\n // Wait for the transaction to be published.\n await result;\n\n return {\n batchId,\n };\n}\n\n/**\n * Determine which chains support atomic batch transactions for the given account.\n *\n * @param request - The request object including the account address and necessary callbacks.\n * @returns The chain IDs that support atomic batch transactions.\n */\nexport async function isAtomicBatchSupported(\n request: IsAtomicBatchSupportedRequest,\n): Promise<Hex[]> {\n const {\n address,\n getEthQuery,\n messenger,\n publicKeyEIP7702: publicKey,\n } = request;\n\n if (!publicKey) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const chainIds7702 = getEIP7702SupportedChains(messenger);\n const chainIds: Hex[] = [];\n\n for (const chainId of chainIds7702) {\n const ethQuery = getEthQuery(chainId);\n\n const { isSupported, delegationAddress } = await isAccountUpgradedToEIP7702(\n address,\n chainId,\n publicKey,\n messenger,\n ethQuery,\n );\n\n if (!delegationAddress || isSupported) {\n chainIds.push(chainId);\n }\n }\n\n log('Atomic batch supported chains', chainIds);\n\n return chainIds;\n}\n\n/**\n * Generate a tranasction batch ID.\n *\n * @returns A unique batch ID as a hexadecimal string.\n */\nfunction generateBatchId(): Hex {\n const idString = v4();\n const idBytes = new Uint8Array(parse(idString));\n return bytesToHex(idBytes);\n}\n\n/**\n * Generate the metadata for a nested transaction.\n *\n * @param request - The batch request.\n * @param singleRequest - The request for a single transaction.\n * @param ethQuery - The EthQuery instance used to interact with the Ethereum blockchain.\n * @returns The metadata for the nested transaction.\n */\nasync function getNestedTransactionMeta(\n request: TransactionBatchRequest,\n singleRequest: TransactionBatchSingleRequest,\n ethQuery: EthQuery,\n): Promise<NestedTransactionMetadata> {\n const { from } = request;\n const { params } = singleRequest;\n\n const { type } = await determineTransactionType(\n { from, ...params },\n ethQuery,\n );\n\n return {\n ...params,\n type,\n };\n}\n"]}
1
+ {"version":3,"file":"batch.mjs","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { bytesToHex, createModuleLogger } from '@metamask/utils';\nimport { parse, v4 } from 'uuid';\n\nimport {\n doesChainSupportEIP7702,\n generateEIP7702BatchTransaction,\n isAccountUpgradedToEIP7702,\n} from './eip7702';\nimport {\n getBatchSizeLimit,\n getEIP7702SupportedChains,\n getEIP7702UpgradeContractAddress,\n} from './feature-flags';\nimport { validateBatchRequest } from './validation';\nimport {\n determineTransactionType,\n type BatchTransactionParams,\n type TransactionController,\n type TransactionControllerMessenger,\n type TransactionMeta,\n} from '..';\nimport { CollectPublishHook } from '../hooks/CollectPublishHook';\nimport { projectLogger } from '../logger';\nimport type {\n NestedTransactionMetadata,\n SecurityAlertResponse,\n TransactionBatchSingleRequest,\n PublishBatchHook,\n PublishBatchHookTransaction,\n PublishHook,\n TransactionBatchRequest,\n ValidateSecurityRequest,\n} from '../types';\nimport {\n TransactionEnvelopeType,\n type TransactionBatchResult,\n type TransactionParams,\n TransactionType,\n} from '../types';\n\ntype AddTransactionBatchRequest = {\n addTransaction: TransactionController['addTransaction'];\n getChainId: (networkClientId: string) => Hex;\n getEthQuery: (networkClientId: string) => EthQuery;\n getInternalAccounts: () => Hex[];\n getTransaction: (id: string) => TransactionMeta;\n messenger: TransactionControllerMessenger;\n publishBatchHook?: PublishBatchHook;\n publicKeyEIP7702?: Hex;\n request: TransactionBatchRequest;\n updateTransaction: (\n options: { transactionId: string },\n callback: (transactionMeta: TransactionMeta) => void,\n ) => void;\n};\n\ntype IsAtomicBatchSupportedRequest = {\n address: Hex;\n getEthQuery: (chainId: Hex) => EthQuery;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n};\n\nconst log = createModuleLogger(projectLogger, 'batch');\n\n/**\n * Add a batch transaction.\n *\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The batch result object including the batch ID.\n */\nexport async function addTransactionBatch(\n request: AddTransactionBatchRequest,\n): Promise<TransactionBatchResult> {\n const {\n addTransaction,\n getChainId,\n getInternalAccounts,\n messenger,\n publicKeyEIP7702,\n request: userRequest,\n } = request;\n\n const sizeLimit = getBatchSizeLimit(messenger);\n\n validateBatchRequest({\n internalAccounts: getInternalAccounts(),\n request: userRequest,\n sizeLimit,\n });\n\n const {\n batchId: batchIdOverride,\n from,\n networkClientId,\n requireApproval,\n securityAlertId,\n transactions,\n useHook,\n validateSecurity,\n } = userRequest;\n\n log('Adding', userRequest);\n\n if (useHook) {\n return await addTransactionBatchWithHook(request);\n }\n\n const chainId = getChainId(networkClientId);\n const ethQuery = request.getEthQuery(networkClientId);\n const isChainSupported = doesChainSupportEIP7702(chainId, messenger);\n\n if (!isChainSupported) {\n log('Chain does not support EIP-7702', chainId);\n throw rpcErrors.internal('Chain does not support EIP-7702');\n }\n\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const { delegationAddress, isSupported } = await isAccountUpgradedToEIP7702(\n from,\n chainId,\n publicKeyEIP7702,\n messenger,\n ethQuery,\n );\n\n log('Account', { delegationAddress, isSupported });\n\n if (!isSupported && delegationAddress) {\n log('Account upgraded to unsupported contract', from, delegationAddress);\n throw rpcErrors.internal('Account upgraded to unsupported contract');\n }\n\n const nestedTransactions = await Promise.all(\n transactions.map((tx) =>\n getNestedTransactionMeta(userRequest, tx, ethQuery),\n ),\n );\n\n const batchParams = generateEIP7702BatchTransaction(from, nestedTransactions);\n\n const txParams: TransactionParams = {\n from,\n ...batchParams,\n };\n\n if (!isSupported) {\n const upgradeContractAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeContractAddress) {\n throw rpcErrors.internal('Upgrade contract address not found');\n }\n\n txParams.type = TransactionEnvelopeType.setCode;\n txParams.authorizationList = [{ address: upgradeContractAddress }];\n }\n\n if (validateSecurity) {\n const securityRequest: ValidateSecurityRequest = {\n method: 'eth_sendTransaction',\n params: [\n {\n ...txParams,\n authorizationList: undefined,\n type: TransactionEnvelopeType.feeMarket,\n },\n ],\n delegationMock: txParams.authorizationList?.[0]?.address,\n };\n\n log('Security request', securityRequest);\n\n validateSecurity(securityRequest, chainId).catch((error) => {\n log('Security validation failed', error);\n });\n }\n\n log('Adding batch transaction', txParams, networkClientId);\n\n const batchId = batchIdOverride ?? generateBatchId();\n\n const securityAlertResponse = securityAlertId\n ? ({ securityAlertId } as SecurityAlertResponse)\n : undefined;\n\n const { result } = await addTransaction(txParams, {\n batchId,\n nestedTransactions,\n networkClientId,\n requireApproval,\n securityAlertResponse,\n type: TransactionType.batch,\n });\n\n // Wait for the transaction to be published.\n await result;\n\n return {\n batchId,\n };\n}\n\n/**\n * Determine which chains support atomic batch transactions for the given account.\n *\n * @param request - The request object including the account address and necessary callbacks.\n * @returns The chain IDs that support atomic batch transactions.\n */\nexport async function isAtomicBatchSupported(\n request: IsAtomicBatchSupportedRequest,\n): Promise<Hex[]> {\n const {\n address,\n getEthQuery,\n messenger,\n publicKeyEIP7702: publicKey,\n } = request;\n\n if (!publicKey) {\n throw rpcErrors.internal('EIP-7702 public key not specified');\n }\n\n const chainIds7702 = getEIP7702SupportedChains(messenger);\n const chainIds: Hex[] = [];\n\n for (const chainId of chainIds7702) {\n const ethQuery = getEthQuery(chainId);\n\n const { isSupported, delegationAddress } = await isAccountUpgradedToEIP7702(\n address,\n chainId,\n publicKey,\n messenger,\n ethQuery,\n );\n\n if (!delegationAddress || isSupported) {\n chainIds.push(chainId);\n }\n }\n\n log('Atomic batch supported chains', chainIds);\n\n return chainIds;\n}\n\n/**\n * Generate a tranasction batch ID.\n *\n * @returns A unique batch ID as a hexadecimal string.\n */\nfunction generateBatchId(): Hex {\n const idString = v4();\n const idBytes = new Uint8Array(parse(idString));\n return bytesToHex(idBytes);\n}\n\n/**\n * Generate the metadata for a nested transaction.\n *\n * @param request - The batch request.\n * @param singleRequest - The request for a single transaction.\n * @param ethQuery - The EthQuery instance used to interact with the Ethereum blockchain.\n * @returns The metadata for the nested transaction.\n */\nasync function getNestedTransactionMeta(\n request: TransactionBatchRequest,\n singleRequest: TransactionBatchSingleRequest,\n ethQuery: EthQuery,\n): Promise<NestedTransactionMetadata> {\n const { from } = request;\n const { params } = singleRequest;\n\n const { type } = await determineTransactionType(\n { from, ...params },\n ethQuery,\n );\n\n return {\n ...params,\n type,\n };\n}\n\n/**\n * Process a batch transaction using a publish batch hook.\n *\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The batch result object including the batch ID.\n */\nasync function addTransactionBatchWithHook(\n request: AddTransactionBatchRequest,\n): Promise<TransactionBatchResult> {\n const { publishBatchHook, request: userRequest } = request;\n\n const {\n from,\n networkClientId,\n transactions: nestedTransactions,\n } = userRequest;\n\n log('Adding transaction batch using hook', userRequest);\n\n if (!publishBatchHook) {\n log('No publish batch hook provided');\n throw new Error('No publish batch hook provided');\n }\n\n const batchId = generateBatchId();\n const transactionCount = nestedTransactions.length;\n const collectHook = new CollectPublishHook(transactionCount);\n const publishHook = collectHook.getHook();\n const hookTransactions: Omit<PublishBatchHookTransaction, 'signedTx'>[] = [];\n\n try {\n for (const nestedTransaction of nestedTransactions) {\n const hookTransaction = await processTransactionWithHook(\n batchId,\n nestedTransaction,\n publishHook,\n request,\n );\n\n hookTransactions.push(hookTransaction);\n }\n\n const { signedTransactions } = await collectHook.ready();\n\n const transactions = hookTransactions.map((transaction, index) => ({\n ...transaction,\n signedTx: signedTransactions[index],\n }));\n\n log('Calling publish batch hook', { from, networkClientId, transactions });\n\n const result = await publishBatchHook({\n from,\n networkClientId,\n transactions,\n });\n\n log('Publish batch hook result', result);\n\n if (!result) {\n throw new Error('Publish batch hook did not return a result');\n }\n\n const transactionHashes = result.results.map(\n ({ transactionHash }) => transactionHash,\n );\n\n collectHook.success(transactionHashes);\n\n log('Completed batch transaction with hook', transactionHashes);\n\n return {\n batchId,\n };\n } catch (error) {\n log('Publish batch hook failed', error);\n\n collectHook.error(error);\n\n throw error;\n }\n}\n\n/**\n * Process a single transaction with a publish batch hook.\n *\n * @param batchId - ID of the transaction batch.\n * @param nestedTransaction - The nested transaction request.\n * @param publishHook - The publish hook to use for each transaction.\n * @param request - The request object including the user request and necessary callbacks.\n * @returns The single transaction request to be processed by the publish batch hook.\n */\nasync function processTransactionWithHook(\n batchId: Hex,\n nestedTransaction: TransactionBatchSingleRequest,\n publishHook: PublishHook,\n request: AddTransactionBatchRequest,\n) {\n const { existingTransaction, params } = nestedTransaction;\n\n const {\n addTransaction,\n getTransaction,\n request: userRequest,\n updateTransaction,\n } = request;\n\n const { from, networkClientId } = userRequest;\n\n if (existingTransaction) {\n const { id, onPublish, signedTransaction } = existingTransaction;\n const transactionMeta = getTransaction(id);\n\n updateTransaction({ transactionId: id }, (_transactionMeta) => {\n _transactionMeta.batchId = batchId;\n });\n\n publishHook(transactionMeta, signedTransaction)\n .then(onPublish)\n .catch(() => {\n // Intentionally empty\n });\n\n log('Processed existing transaction with hook', {\n id,\n params,\n });\n\n return {\n id,\n params,\n };\n }\n\n const { transactionMeta } = await addTransaction(\n {\n ...params,\n from,\n },\n {\n batchId,\n disableGasBuffer: true,\n networkClientId,\n publishHook,\n requireApproval: false,\n },\n );\n\n const { id, txParams } = transactionMeta;\n const data = txParams.data as Hex | undefined;\n const gas = txParams.gas as Hex | undefined;\n const maxFeePerGas = txParams.maxFeePerGas as Hex | undefined;\n const maxPriorityFeePerGas = txParams.maxPriorityFeePerGas as Hex | undefined;\n const to = txParams.to as Hex | undefined;\n const value = txParams.value as Hex | undefined;\n\n const newParams: BatchTransactionParams = {\n data,\n gas,\n maxFeePerGas,\n maxPriorityFeePerGas,\n to,\n value,\n };\n\n log('Processed new transaction with hook', { id, params: newParams });\n\n return {\n id,\n params: newParams,\n };\n}\n"]}
@@ -11,6 +11,11 @@ const logger_1 = require("../logger.cjs");
11
11
  exports.DELEGATION_PREFIX = '0xef0100';
12
12
  exports.BATCH_FUNCTION_NAME = 'execute';
13
13
  exports.CALLS_SIGNATURE = '(address,uint256,bytes)[]';
14
+ const UNSUPPORTED_PARAMS = [
15
+ 'gas',
16
+ 'maxFeePerGas',
17
+ 'maxPriorityFeePerGas',
18
+ ];
14
19
  const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'eip-7702');
15
20
  /**
16
21
  * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
@@ -72,6 +77,13 @@ function generateEIP7702BatchTransaction(from, transactions) {
72
77
  const erc7821Contract = contracts_1.Contract.getInterface(constants_1.ABI_IERC7821);
73
78
  const calls = transactions.map((transaction) => {
74
79
  const { data, to, value } = transaction;
80
+ const unsupported = UNSUPPORTED_PARAMS.filter((param) => transaction[param] !== undefined);
81
+ if (unsupported.length) {
82
+ const errorData = unsupported
83
+ .map((param) => `${param}: ${transaction[param]}`)
84
+ .join(', ');
85
+ throw new Error(`EIP-7702 batch transactions do not support gas parameters per call - ${errorData}`);
86
+ }
75
87
  return [
76
88
  to ?? '0x0000000000000000000000000000000000000000',
77
89
  value ?? '0x0',