@metamask/transaction-controller 56.1.0 → 56.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 (44) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/TransactionController.cjs +8 -0
  3. package/dist/TransactionController.cjs.map +1 -1
  4. package/dist/TransactionController.d.cts.map +1 -1
  5. package/dist/TransactionController.d.mts.map +1 -1
  6. package/dist/TransactionController.mjs +9 -1
  7. package/dist/TransactionController.mjs.map +1 -1
  8. package/dist/helpers/PendingTransactionTracker.cjs +34 -3
  9. package/dist/helpers/PendingTransactionTracker.cjs.map +1 -1
  10. package/dist/helpers/PendingTransactionTracker.d.cts +12 -0
  11. package/dist/helpers/PendingTransactionTracker.d.cts.map +1 -1
  12. package/dist/helpers/PendingTransactionTracker.d.mts +12 -0
  13. package/dist/helpers/PendingTransactionTracker.d.mts.map +1 -1
  14. package/dist/helpers/PendingTransactionTracker.mjs +34 -3
  15. package/dist/helpers/PendingTransactionTracker.mjs.map +1 -1
  16. package/dist/hooks/SequentialPublishBatchHook.cjs +114 -0
  17. package/dist/hooks/SequentialPublishBatchHook.cjs.map +1 -0
  18. package/dist/hooks/SequentialPublishBatchHook.d.cts +24 -0
  19. package/dist/hooks/SequentialPublishBatchHook.d.cts.map +1 -0
  20. package/dist/hooks/SequentialPublishBatchHook.d.mts +24 -0
  21. package/dist/hooks/SequentialPublishBatchHook.d.mts.map +1 -0
  22. package/dist/hooks/SequentialPublishBatchHook.mjs +110 -0
  23. package/dist/hooks/SequentialPublishBatchHook.mjs.map +1 -0
  24. package/dist/utils/batch.cjs +12 -6
  25. package/dist/utils/batch.cjs.map +1 -1
  26. package/dist/utils/batch.d.cts +3 -0
  27. package/dist/utils/batch.d.cts.map +1 -1
  28. package/dist/utils/batch.d.mts +3 -0
  29. package/dist/utils/batch.d.mts.map +1 -1
  30. package/dist/utils/batch.mjs +12 -6
  31. package/dist/utils/batch.mjs.map +1 -1
  32. package/dist/utils/gas-fees.cjs +3 -7
  33. package/dist/utils/gas-fees.cjs.map +1 -1
  34. package/dist/utils/gas-fees.d.cts.map +1 -1
  35. package/dist/utils/gas-fees.d.mts.map +1 -1
  36. package/dist/utils/gas-fees.mjs +3 -7
  37. package/dist/utils/gas-fees.mjs.map +1 -1
  38. package/dist/utils/transaction-type.cjs +4 -1
  39. package/dist/utils/transaction-type.cjs.map +1 -1
  40. package/dist/utils/transaction-type.d.cts.map +1 -1
  41. package/dist/utils/transaction-type.d.mts.map +1 -1
  42. package/dist/utils/transaction-type.mjs +4 -1
  43. package/dist/utils/transaction-type.mjs.map +1 -1
  44. package/package.json +1 -1
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _SequentialPublishBatchHook_instances, _SequentialPublishBatchHook_publishTransaction, _SequentialPublishBatchHook_getTransaction, _SequentialPublishBatchHook_getEthQuery, _SequentialPublishBatchHook_getPendingTransactionTracker, _SequentialPublishBatchHook_boundListeners, _SequentialPublishBatchHook_hook, _SequentialPublishBatchHook_waitForTransactionEvent, _SequentialPublishBatchHook_onConfirmed, _SequentialPublishBatchHook_onFailedOrDropped, _SequentialPublishBatchHook_removeListeners;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SequentialPublishBatchHook = void 0;
16
+ const rpc_errors_1 = require("@metamask/rpc-errors");
17
+ const utils_1 = require("@metamask/utils");
18
+ const logger_1 = require("../logger.cjs");
19
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'sequential-publish-batch-hook');
20
+ /**
21
+ * Custom publish logic that also publishes additional sequential transactions in a batch.
22
+ * Requires the batch to be successful to resolve.
23
+ */
24
+ class SequentialPublishBatchHook {
25
+ constructor({ publishTransaction, getTransaction, getPendingTransactionTracker, getEthQuery, }) {
26
+ _SequentialPublishBatchHook_instances.add(this);
27
+ _SequentialPublishBatchHook_publishTransaction.set(this, void 0);
28
+ _SequentialPublishBatchHook_getTransaction.set(this, void 0);
29
+ _SequentialPublishBatchHook_getEthQuery.set(this, void 0);
30
+ _SequentialPublishBatchHook_getPendingTransactionTracker.set(this, void 0);
31
+ _SequentialPublishBatchHook_boundListeners.set(this, {});
32
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_publishTransaction, publishTransaction, "f");
33
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_getTransaction, getTransaction, "f");
34
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_getEthQuery, getEthQuery, "f");
35
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_getPendingTransactionTracker, getPendingTransactionTracker, "f");
36
+ }
37
+ /**
38
+ * @returns The publish batch hook function.
39
+ */
40
+ getHook() {
41
+ return __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_hook).bind(this);
42
+ }
43
+ }
44
+ exports.SequentialPublishBatchHook = SequentialPublishBatchHook;
45
+ _SequentialPublishBatchHook_publishTransaction = new WeakMap(), _SequentialPublishBatchHook_getTransaction = new WeakMap(), _SequentialPublishBatchHook_getEthQuery = new WeakMap(), _SequentialPublishBatchHook_getPendingTransactionTracker = new WeakMap(), _SequentialPublishBatchHook_boundListeners = new WeakMap(), _SequentialPublishBatchHook_instances = new WeakSet(), _SequentialPublishBatchHook_hook = async function _SequentialPublishBatchHook_hook({ from, networkClientId, transactions, }) {
46
+ log('Starting sequential publish batch hook', { from, networkClientId });
47
+ const pendingTransactionTracker = __classPrivateFieldGet(this, _SequentialPublishBatchHook_getPendingTransactionTracker, "f").call(this, networkClientId);
48
+ const results = [];
49
+ for (const transaction of transactions) {
50
+ try {
51
+ const transactionMeta = __classPrivateFieldGet(this, _SequentialPublishBatchHook_getTransaction, "f").call(this, String(transaction.id));
52
+ const transactionHash = await __classPrivateFieldGet(this, _SequentialPublishBatchHook_publishTransaction, "f").call(this, __classPrivateFieldGet(this, _SequentialPublishBatchHook_getEthQuery, "f").call(this, networkClientId), transactionMeta);
53
+ log('Transaction published', { transactionHash });
54
+ const transactionUpdated = {
55
+ ...transactionMeta,
56
+ hash: transactionHash,
57
+ };
58
+ const confirmationPromise = __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_waitForTransactionEvent).call(this, pendingTransactionTracker, transactionUpdated.id, transactionUpdated.hash);
59
+ pendingTransactionTracker.addTransactionToPoll(transactionUpdated);
60
+ await confirmationPromise;
61
+ results.push({ transactionHash });
62
+ }
63
+ catch (error) {
64
+ log('Batch transaction failed', { transaction, error });
65
+ pendingTransactionTracker.stop();
66
+ throw rpc_errors_1.rpcErrors.internal(`Failed to publish batch transaction`);
67
+ }
68
+ }
69
+ log('Sequential publish batch hook completed', { results });
70
+ pendingTransactionTracker.stop();
71
+ return { results };
72
+ }, _SequentialPublishBatchHook_waitForTransactionEvent =
73
+ /**
74
+ * Waits for a transaction event (confirmed, failed, or dropped) and resolves/rejects accordingly.
75
+ *
76
+ * @param pendingTransactionTracker - The tracker instance to subscribe to events.
77
+ * @param transactionId - The transaction ID.
78
+ * @param transactionHash - The hash of the transaction.
79
+ * @returns A promise that resolves when the transaction is confirmed or rejects if it fails or is dropped.
80
+ */
81
+ async function _SequentialPublishBatchHook_waitForTransactionEvent(pendingTransactionTracker, transactionId, transactionHash) {
82
+ return new Promise((resolve, reject) => {
83
+ const onConfirmed = __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_onConfirmed).bind(this, transactionId, transactionHash, resolve, pendingTransactionTracker);
84
+ const onFailedOrDropped = __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_onFailedOrDropped).bind(this, transactionId, transactionHash, reject, pendingTransactionTracker);
85
+ __classPrivateFieldGet(this, _SequentialPublishBatchHook_boundListeners, "f")[transactionId] = {
86
+ onConfirmed,
87
+ onFailedOrDropped,
88
+ };
89
+ pendingTransactionTracker.hub.on('transaction-confirmed', onConfirmed);
90
+ pendingTransactionTracker.hub.on('transaction-failed', onFailedOrDropped);
91
+ pendingTransactionTracker.hub.on('transaction-dropped', onFailedOrDropped);
92
+ });
93
+ }, _SequentialPublishBatchHook_onConfirmed = function _SequentialPublishBatchHook_onConfirmed(transactionId, transactionHash, resolve, pendingTransactionTracker, txMeta) {
94
+ if (txMeta.id !== transactionId) {
95
+ return;
96
+ }
97
+ log('Transaction confirmed', { transactionHash });
98
+ __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_removeListeners).call(this, pendingTransactionTracker, transactionId);
99
+ resolve(txMeta);
100
+ }, _SequentialPublishBatchHook_onFailedOrDropped = function _SequentialPublishBatchHook_onFailedOrDropped(transactionId, transactionHash, reject, pendingTransactionTracker, txMeta, error) {
101
+ if (txMeta.id !== transactionId) {
102
+ return;
103
+ }
104
+ log('Transaction failed or dropped', { transactionHash, error });
105
+ __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_removeListeners).call(this, pendingTransactionTracker, transactionId);
106
+ reject(new Error(`Transaction ${transactionHash} failed or dropped.`));
107
+ }, _SequentialPublishBatchHook_removeListeners = function _SequentialPublishBatchHook_removeListeners(pendingTransactionTracker, transactionId) {
108
+ const listeners = __classPrivateFieldGet(this, _SequentialPublishBatchHook_boundListeners, "f")[transactionId];
109
+ pendingTransactionTracker.hub.off('transaction-confirmed', listeners.onConfirmed);
110
+ pendingTransactionTracker.hub.off('transaction-failed', listeners.onFailedOrDropped);
111
+ pendingTransactionTracker.hub.off('transaction-dropped', listeners.onFailedOrDropped);
112
+ delete __classPrivateFieldGet(this, _SequentialPublishBatchHook_boundListeners, "f")[transactionId];
113
+ };
114
+ //# sourceMappingURL=SequentialPublishBatchHook.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SequentialPublishBatchHook.cjs","sourceRoot":"","sources":["../../src/hooks/SequentialPublishBatchHook.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { PendingTransactionTracker } from '../helpers/PendingTransactionTracker';\nimport { projectLogger } from '../logger';\nimport {\n type PublishBatchHook,\n type PublishBatchHookRequest,\n type PublishBatchHookResult,\n type TransactionMeta,\n} from '../types';\n\nconst log = createModuleLogger(projectLogger, 'sequential-publish-batch-hook');\n\ntype SequentialPublishBatchHookOptions = {\n publishTransaction: (\n ethQuery: EthQuery,\n transactionMeta: TransactionMeta,\n ) => Promise<Hex>;\n getTransaction: (id: string) => TransactionMeta;\n getEthQuery: (networkClientId: string) => EthQuery;\n getPendingTransactionTracker: (\n networkClientId: string,\n ) => PendingTransactionTracker;\n};\n\n/**\n * Custom publish logic that also publishes additional sequential transactions in a batch.\n * Requires the batch to be successful to resolve.\n */\nexport class SequentialPublishBatchHook {\n readonly #publishTransaction: (\n ethQuery: EthQuery,\n transactionMeta: TransactionMeta,\n ) => Promise<Hex>;\n\n readonly #getTransaction: (id: string) => TransactionMeta;\n\n readonly #getEthQuery: (networkClientId: string) => EthQuery;\n\n readonly #getPendingTransactionTracker: (\n networkClientId: string,\n ) => PendingTransactionTracker;\n\n #boundListeners: Record<\n string,\n {\n onConfirmed: (txMeta: TransactionMeta) => void;\n onFailedOrDropped: (txMeta: TransactionMeta, error?: Error) => void;\n }\n > = {};\n\n constructor({\n publishTransaction,\n getTransaction,\n getPendingTransactionTracker,\n getEthQuery,\n }: SequentialPublishBatchHookOptions) {\n this.#publishTransaction = publishTransaction;\n this.#getTransaction = getTransaction;\n this.#getEthQuery = getEthQuery;\n this.#getPendingTransactionTracker = getPendingTransactionTracker;\n }\n\n /**\n * @returns The publish batch hook function.\n */\n getHook(): PublishBatchHook {\n return this.#hook.bind(this);\n }\n\n async #hook({\n from,\n networkClientId,\n transactions,\n }: PublishBatchHookRequest): Promise<PublishBatchHookResult> {\n log('Starting sequential publish batch hook', { from, networkClientId });\n\n const pendingTransactionTracker =\n this.#getPendingTransactionTracker(networkClientId);\n const results = [];\n\n for (const transaction of transactions) {\n try {\n const transactionMeta = this.#getTransaction(String(transaction.id));\n\n const transactionHash = await this.#publishTransaction(\n this.#getEthQuery(networkClientId),\n transactionMeta,\n );\n log('Transaction published', { transactionHash });\n\n const transactionUpdated = {\n ...transactionMeta,\n hash: transactionHash,\n };\n\n const confirmationPromise = this.#waitForTransactionEvent(\n pendingTransactionTracker,\n transactionUpdated.id,\n transactionUpdated.hash,\n );\n\n pendingTransactionTracker.addTransactionToPoll(transactionUpdated);\n\n await confirmationPromise;\n results.push({ transactionHash });\n } catch (error) {\n log('Batch transaction failed', { transaction, error });\n pendingTransactionTracker.stop();\n throw rpcErrors.internal(`Failed to publish batch transaction`);\n }\n }\n\n log('Sequential publish batch hook completed', { results });\n pendingTransactionTracker.stop();\n\n return { results };\n }\n\n /**\n * Waits for a transaction event (confirmed, failed, or dropped) and resolves/rejects accordingly.\n *\n * @param pendingTransactionTracker - The tracker instance to subscribe to events.\n * @param transactionId - The transaction ID.\n * @param transactionHash - The hash of the transaction.\n * @returns A promise that resolves when the transaction is confirmed or rejects if it fails or is dropped.\n */\n async #waitForTransactionEvent(\n pendingTransactionTracker: PendingTransactionTracker,\n transactionId: string,\n transactionHash: string,\n ): Promise<TransactionMeta> {\n return new Promise((resolve, reject) => {\n const onConfirmed = this.#onConfirmed.bind(\n this,\n transactionId,\n transactionHash,\n resolve,\n pendingTransactionTracker,\n );\n\n const onFailedOrDropped = this.#onFailedOrDropped.bind(\n this,\n transactionId,\n transactionHash,\n reject,\n pendingTransactionTracker,\n );\n\n this.#boundListeners[transactionId] = {\n onConfirmed,\n onFailedOrDropped,\n };\n\n pendingTransactionTracker.hub.on('transaction-confirmed', onConfirmed);\n pendingTransactionTracker.hub.on('transaction-failed', onFailedOrDropped);\n pendingTransactionTracker.hub.on(\n 'transaction-dropped',\n onFailedOrDropped,\n );\n });\n }\n\n #onConfirmed(\n transactionId: string,\n transactionHash: string,\n resolve: (txMeta: TransactionMeta) => void,\n pendingTransactionTracker: PendingTransactionTracker,\n txMeta: TransactionMeta,\n ): void {\n if (txMeta.id !== transactionId) {\n return;\n }\n\n log('Transaction confirmed', { transactionHash });\n this.#removeListeners(pendingTransactionTracker, transactionId);\n resolve(txMeta);\n }\n\n #onFailedOrDropped(\n transactionId: string,\n transactionHash: string,\n reject: (error: Error) => void,\n pendingTransactionTracker: PendingTransactionTracker,\n txMeta: TransactionMeta,\n error?: Error,\n ): void {\n if (txMeta.id !== transactionId) {\n return;\n }\n\n log('Transaction failed or dropped', { transactionHash, error });\n this.#removeListeners(pendingTransactionTracker, transactionId);\n reject(new Error(`Transaction ${transactionHash} failed or dropped.`));\n }\n\n #removeListeners(\n pendingTransactionTracker: PendingTransactionTracker,\n transactionId: string,\n ): void {\n const listeners = this.#boundListeners[transactionId];\n\n pendingTransactionTracker.hub.off(\n 'transaction-confirmed',\n listeners.onConfirmed,\n );\n pendingTransactionTracker.hub.off(\n 'transaction-failed',\n listeners.onFailedOrDropped,\n );\n pendingTransactionTracker.hub.off(\n 'transaction-dropped',\n listeners.onFailedOrDropped,\n );\n\n delete this.#boundListeners[transactionId];\n }\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import type EthQuery from "@metamask/eth-query";
2
+ import type { Hex } from "@metamask/utils";
3
+ import type { PendingTransactionTracker } from "../helpers/PendingTransactionTracker.cjs";
4
+ import { type PublishBatchHook, type TransactionMeta } from "../types.cjs";
5
+ type SequentialPublishBatchHookOptions = {
6
+ publishTransaction: (ethQuery: EthQuery, transactionMeta: TransactionMeta) => Promise<Hex>;
7
+ getTransaction: (id: string) => TransactionMeta;
8
+ getEthQuery: (networkClientId: string) => EthQuery;
9
+ getPendingTransactionTracker: (networkClientId: string) => PendingTransactionTracker;
10
+ };
11
+ /**
12
+ * Custom publish logic that also publishes additional sequential transactions in a batch.
13
+ * Requires the batch to be successful to resolve.
14
+ */
15
+ export declare class SequentialPublishBatchHook {
16
+ #private;
17
+ constructor({ publishTransaction, getTransaction, getPendingTransactionTracker, getEthQuery, }: SequentialPublishBatchHookOptions);
18
+ /**
19
+ * @returns The publish batch hook function.
20
+ */
21
+ getHook(): PublishBatchHook;
22
+ }
23
+ export {};
24
+ //# sourceMappingURL=SequentialPublishBatchHook.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SequentialPublishBatchHook.d.cts","sourceRoot":"","sources":["../../src/hooks/SequentialPublishBatchHook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAGhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,EAAE,yBAAyB,EAAE,iDAA6C;AAEtF,OAAO,EACL,KAAK,gBAAgB,EAGrB,KAAK,eAAe,EACrB,qBAAiB;AAIlB,KAAK,iCAAiC,GAAG;IACvC,kBAAkB,EAAE,CAClB,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,eAAe,CAAC;IAChD,WAAW,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,QAAQ,CAAC;IACnD,4BAA4B,EAAE,CAC5B,eAAe,EAAE,MAAM,KACpB,yBAAyB,CAAC;CAChC,CAAC;AAEF;;;GAGG;AACH,qBAAa,0BAA0B;;gBAsBzB,EACV,kBAAkB,EAClB,cAAc,EACd,4BAA4B,EAC5B,WAAW,GACZ,EAAE,iCAAiC;IAOpC;;OAEG;IACH,OAAO,IAAI,gBAAgB;CAuJ5B"}
@@ -0,0 +1,24 @@
1
+ import type EthQuery from "@metamask/eth-query";
2
+ import type { Hex } from "@metamask/utils";
3
+ import type { PendingTransactionTracker } from "../helpers/PendingTransactionTracker.mjs";
4
+ import { type PublishBatchHook, type TransactionMeta } from "../types.mjs";
5
+ type SequentialPublishBatchHookOptions = {
6
+ publishTransaction: (ethQuery: EthQuery, transactionMeta: TransactionMeta) => Promise<Hex>;
7
+ getTransaction: (id: string) => TransactionMeta;
8
+ getEthQuery: (networkClientId: string) => EthQuery;
9
+ getPendingTransactionTracker: (networkClientId: string) => PendingTransactionTracker;
10
+ };
11
+ /**
12
+ * Custom publish logic that also publishes additional sequential transactions in a batch.
13
+ * Requires the batch to be successful to resolve.
14
+ */
15
+ export declare class SequentialPublishBatchHook {
16
+ #private;
17
+ constructor({ publishTransaction, getTransaction, getPendingTransactionTracker, getEthQuery, }: SequentialPublishBatchHookOptions);
18
+ /**
19
+ * @returns The publish batch hook function.
20
+ */
21
+ getHook(): PublishBatchHook;
22
+ }
23
+ export {};
24
+ //# sourceMappingURL=SequentialPublishBatchHook.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SequentialPublishBatchHook.d.mts","sourceRoot":"","sources":["../../src/hooks/SequentialPublishBatchHook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAGhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,EAAE,yBAAyB,EAAE,iDAA6C;AAEtF,OAAO,EACL,KAAK,gBAAgB,EAGrB,KAAK,eAAe,EACrB,qBAAiB;AAIlB,KAAK,iCAAiC,GAAG;IACvC,kBAAkB,EAAE,CAClB,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,eAAe,CAAC;IAChD,WAAW,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,QAAQ,CAAC;IACnD,4BAA4B,EAAE,CAC5B,eAAe,EAAE,MAAM,KACpB,yBAAyB,CAAC;CAChC,CAAC;AAEF;;;GAGG;AACH,qBAAa,0BAA0B;;gBAsBzB,EACV,kBAAkB,EAClB,cAAc,EACd,4BAA4B,EAC5B,WAAW,GACZ,EAAE,iCAAiC;IAOpC;;OAEG;IACH,OAAO,IAAI,gBAAgB;CAuJ5B"}
@@ -0,0 +1,110 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _SequentialPublishBatchHook_instances, _SequentialPublishBatchHook_publishTransaction, _SequentialPublishBatchHook_getTransaction, _SequentialPublishBatchHook_getEthQuery, _SequentialPublishBatchHook_getPendingTransactionTracker, _SequentialPublishBatchHook_boundListeners, _SequentialPublishBatchHook_hook, _SequentialPublishBatchHook_waitForTransactionEvent, _SequentialPublishBatchHook_onConfirmed, _SequentialPublishBatchHook_onFailedOrDropped, _SequentialPublishBatchHook_removeListeners;
13
+ import { rpcErrors } from "@metamask/rpc-errors";
14
+ import { createModuleLogger } from "@metamask/utils";
15
+ import { projectLogger } from "../logger.mjs";
16
+ const log = createModuleLogger(projectLogger, 'sequential-publish-batch-hook');
17
+ /**
18
+ * Custom publish logic that also publishes additional sequential transactions in a batch.
19
+ * Requires the batch to be successful to resolve.
20
+ */
21
+ export class SequentialPublishBatchHook {
22
+ constructor({ publishTransaction, getTransaction, getPendingTransactionTracker, getEthQuery, }) {
23
+ _SequentialPublishBatchHook_instances.add(this);
24
+ _SequentialPublishBatchHook_publishTransaction.set(this, void 0);
25
+ _SequentialPublishBatchHook_getTransaction.set(this, void 0);
26
+ _SequentialPublishBatchHook_getEthQuery.set(this, void 0);
27
+ _SequentialPublishBatchHook_getPendingTransactionTracker.set(this, void 0);
28
+ _SequentialPublishBatchHook_boundListeners.set(this, {});
29
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_publishTransaction, publishTransaction, "f");
30
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_getTransaction, getTransaction, "f");
31
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_getEthQuery, getEthQuery, "f");
32
+ __classPrivateFieldSet(this, _SequentialPublishBatchHook_getPendingTransactionTracker, getPendingTransactionTracker, "f");
33
+ }
34
+ /**
35
+ * @returns The publish batch hook function.
36
+ */
37
+ getHook() {
38
+ return __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_hook).bind(this);
39
+ }
40
+ }
41
+ _SequentialPublishBatchHook_publishTransaction = new WeakMap(), _SequentialPublishBatchHook_getTransaction = new WeakMap(), _SequentialPublishBatchHook_getEthQuery = new WeakMap(), _SequentialPublishBatchHook_getPendingTransactionTracker = new WeakMap(), _SequentialPublishBatchHook_boundListeners = new WeakMap(), _SequentialPublishBatchHook_instances = new WeakSet(), _SequentialPublishBatchHook_hook = async function _SequentialPublishBatchHook_hook({ from, networkClientId, transactions, }) {
42
+ log('Starting sequential publish batch hook', { from, networkClientId });
43
+ const pendingTransactionTracker = __classPrivateFieldGet(this, _SequentialPublishBatchHook_getPendingTransactionTracker, "f").call(this, networkClientId);
44
+ const results = [];
45
+ for (const transaction of transactions) {
46
+ try {
47
+ const transactionMeta = __classPrivateFieldGet(this, _SequentialPublishBatchHook_getTransaction, "f").call(this, String(transaction.id));
48
+ const transactionHash = await __classPrivateFieldGet(this, _SequentialPublishBatchHook_publishTransaction, "f").call(this, __classPrivateFieldGet(this, _SequentialPublishBatchHook_getEthQuery, "f").call(this, networkClientId), transactionMeta);
49
+ log('Transaction published', { transactionHash });
50
+ const transactionUpdated = {
51
+ ...transactionMeta,
52
+ hash: transactionHash,
53
+ };
54
+ const confirmationPromise = __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_waitForTransactionEvent).call(this, pendingTransactionTracker, transactionUpdated.id, transactionUpdated.hash);
55
+ pendingTransactionTracker.addTransactionToPoll(transactionUpdated);
56
+ await confirmationPromise;
57
+ results.push({ transactionHash });
58
+ }
59
+ catch (error) {
60
+ log('Batch transaction failed', { transaction, error });
61
+ pendingTransactionTracker.stop();
62
+ throw rpcErrors.internal(`Failed to publish batch transaction`);
63
+ }
64
+ }
65
+ log('Sequential publish batch hook completed', { results });
66
+ pendingTransactionTracker.stop();
67
+ return { results };
68
+ }, _SequentialPublishBatchHook_waitForTransactionEvent =
69
+ /**
70
+ * Waits for a transaction event (confirmed, failed, or dropped) and resolves/rejects accordingly.
71
+ *
72
+ * @param pendingTransactionTracker - The tracker instance to subscribe to events.
73
+ * @param transactionId - The transaction ID.
74
+ * @param transactionHash - The hash of the transaction.
75
+ * @returns A promise that resolves when the transaction is confirmed or rejects if it fails or is dropped.
76
+ */
77
+ async function _SequentialPublishBatchHook_waitForTransactionEvent(pendingTransactionTracker, transactionId, transactionHash) {
78
+ return new Promise((resolve, reject) => {
79
+ const onConfirmed = __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_onConfirmed).bind(this, transactionId, transactionHash, resolve, pendingTransactionTracker);
80
+ const onFailedOrDropped = __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_onFailedOrDropped).bind(this, transactionId, transactionHash, reject, pendingTransactionTracker);
81
+ __classPrivateFieldGet(this, _SequentialPublishBatchHook_boundListeners, "f")[transactionId] = {
82
+ onConfirmed,
83
+ onFailedOrDropped,
84
+ };
85
+ pendingTransactionTracker.hub.on('transaction-confirmed', onConfirmed);
86
+ pendingTransactionTracker.hub.on('transaction-failed', onFailedOrDropped);
87
+ pendingTransactionTracker.hub.on('transaction-dropped', onFailedOrDropped);
88
+ });
89
+ }, _SequentialPublishBatchHook_onConfirmed = function _SequentialPublishBatchHook_onConfirmed(transactionId, transactionHash, resolve, pendingTransactionTracker, txMeta) {
90
+ if (txMeta.id !== transactionId) {
91
+ return;
92
+ }
93
+ log('Transaction confirmed', { transactionHash });
94
+ __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_removeListeners).call(this, pendingTransactionTracker, transactionId);
95
+ resolve(txMeta);
96
+ }, _SequentialPublishBatchHook_onFailedOrDropped = function _SequentialPublishBatchHook_onFailedOrDropped(transactionId, transactionHash, reject, pendingTransactionTracker, txMeta, error) {
97
+ if (txMeta.id !== transactionId) {
98
+ return;
99
+ }
100
+ log('Transaction failed or dropped', { transactionHash, error });
101
+ __classPrivateFieldGet(this, _SequentialPublishBatchHook_instances, "m", _SequentialPublishBatchHook_removeListeners).call(this, pendingTransactionTracker, transactionId);
102
+ reject(new Error(`Transaction ${transactionHash} failed or dropped.`));
103
+ }, _SequentialPublishBatchHook_removeListeners = function _SequentialPublishBatchHook_removeListeners(pendingTransactionTracker, transactionId) {
104
+ const listeners = __classPrivateFieldGet(this, _SequentialPublishBatchHook_boundListeners, "f")[transactionId];
105
+ pendingTransactionTracker.hub.off('transaction-confirmed', listeners.onConfirmed);
106
+ pendingTransactionTracker.hub.off('transaction-failed', listeners.onFailedOrDropped);
107
+ pendingTransactionTracker.hub.off('transaction-dropped', listeners.onFailedOrDropped);
108
+ delete __classPrivateFieldGet(this, _SequentialPublishBatchHook_boundListeners, "f")[transactionId];
109
+ };
110
+ //# sourceMappingURL=SequentialPublishBatchHook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SequentialPublishBatchHook.mjs","sourceRoot":"","sources":["../../src/hooks/SequentialPublishBatchHook.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { PendingTransactionTracker } from '../helpers/PendingTransactionTracker';\nimport { projectLogger } from '../logger';\nimport {\n type PublishBatchHook,\n type PublishBatchHookRequest,\n type PublishBatchHookResult,\n type TransactionMeta,\n} from '../types';\n\nconst log = createModuleLogger(projectLogger, 'sequential-publish-batch-hook');\n\ntype SequentialPublishBatchHookOptions = {\n publishTransaction: (\n ethQuery: EthQuery,\n transactionMeta: TransactionMeta,\n ) => Promise<Hex>;\n getTransaction: (id: string) => TransactionMeta;\n getEthQuery: (networkClientId: string) => EthQuery;\n getPendingTransactionTracker: (\n networkClientId: string,\n ) => PendingTransactionTracker;\n};\n\n/**\n * Custom publish logic that also publishes additional sequential transactions in a batch.\n * Requires the batch to be successful to resolve.\n */\nexport class SequentialPublishBatchHook {\n readonly #publishTransaction: (\n ethQuery: EthQuery,\n transactionMeta: TransactionMeta,\n ) => Promise<Hex>;\n\n readonly #getTransaction: (id: string) => TransactionMeta;\n\n readonly #getEthQuery: (networkClientId: string) => EthQuery;\n\n readonly #getPendingTransactionTracker: (\n networkClientId: string,\n ) => PendingTransactionTracker;\n\n #boundListeners: Record<\n string,\n {\n onConfirmed: (txMeta: TransactionMeta) => void;\n onFailedOrDropped: (txMeta: TransactionMeta, error?: Error) => void;\n }\n > = {};\n\n constructor({\n publishTransaction,\n getTransaction,\n getPendingTransactionTracker,\n getEthQuery,\n }: SequentialPublishBatchHookOptions) {\n this.#publishTransaction = publishTransaction;\n this.#getTransaction = getTransaction;\n this.#getEthQuery = getEthQuery;\n this.#getPendingTransactionTracker = getPendingTransactionTracker;\n }\n\n /**\n * @returns The publish batch hook function.\n */\n getHook(): PublishBatchHook {\n return this.#hook.bind(this);\n }\n\n async #hook({\n from,\n networkClientId,\n transactions,\n }: PublishBatchHookRequest): Promise<PublishBatchHookResult> {\n log('Starting sequential publish batch hook', { from, networkClientId });\n\n const pendingTransactionTracker =\n this.#getPendingTransactionTracker(networkClientId);\n const results = [];\n\n for (const transaction of transactions) {\n try {\n const transactionMeta = this.#getTransaction(String(transaction.id));\n\n const transactionHash = await this.#publishTransaction(\n this.#getEthQuery(networkClientId),\n transactionMeta,\n );\n log('Transaction published', { transactionHash });\n\n const transactionUpdated = {\n ...transactionMeta,\n hash: transactionHash,\n };\n\n const confirmationPromise = this.#waitForTransactionEvent(\n pendingTransactionTracker,\n transactionUpdated.id,\n transactionUpdated.hash,\n );\n\n pendingTransactionTracker.addTransactionToPoll(transactionUpdated);\n\n await confirmationPromise;\n results.push({ transactionHash });\n } catch (error) {\n log('Batch transaction failed', { transaction, error });\n pendingTransactionTracker.stop();\n throw rpcErrors.internal(`Failed to publish batch transaction`);\n }\n }\n\n log('Sequential publish batch hook completed', { results });\n pendingTransactionTracker.stop();\n\n return { results };\n }\n\n /**\n * Waits for a transaction event (confirmed, failed, or dropped) and resolves/rejects accordingly.\n *\n * @param pendingTransactionTracker - The tracker instance to subscribe to events.\n * @param transactionId - The transaction ID.\n * @param transactionHash - The hash of the transaction.\n * @returns A promise that resolves when the transaction is confirmed or rejects if it fails or is dropped.\n */\n async #waitForTransactionEvent(\n pendingTransactionTracker: PendingTransactionTracker,\n transactionId: string,\n transactionHash: string,\n ): Promise<TransactionMeta> {\n return new Promise((resolve, reject) => {\n const onConfirmed = this.#onConfirmed.bind(\n this,\n transactionId,\n transactionHash,\n resolve,\n pendingTransactionTracker,\n );\n\n const onFailedOrDropped = this.#onFailedOrDropped.bind(\n this,\n transactionId,\n transactionHash,\n reject,\n pendingTransactionTracker,\n );\n\n this.#boundListeners[transactionId] = {\n onConfirmed,\n onFailedOrDropped,\n };\n\n pendingTransactionTracker.hub.on('transaction-confirmed', onConfirmed);\n pendingTransactionTracker.hub.on('transaction-failed', onFailedOrDropped);\n pendingTransactionTracker.hub.on(\n 'transaction-dropped',\n onFailedOrDropped,\n );\n });\n }\n\n #onConfirmed(\n transactionId: string,\n transactionHash: string,\n resolve: (txMeta: TransactionMeta) => void,\n pendingTransactionTracker: PendingTransactionTracker,\n txMeta: TransactionMeta,\n ): void {\n if (txMeta.id !== transactionId) {\n return;\n }\n\n log('Transaction confirmed', { transactionHash });\n this.#removeListeners(pendingTransactionTracker, transactionId);\n resolve(txMeta);\n }\n\n #onFailedOrDropped(\n transactionId: string,\n transactionHash: string,\n reject: (error: Error) => void,\n pendingTransactionTracker: PendingTransactionTracker,\n txMeta: TransactionMeta,\n error?: Error,\n ): void {\n if (txMeta.id !== transactionId) {\n return;\n }\n\n log('Transaction failed or dropped', { transactionHash, error });\n this.#removeListeners(pendingTransactionTracker, transactionId);\n reject(new Error(`Transaction ${transactionHash} failed or dropped.`));\n }\n\n #removeListeners(\n pendingTransactionTracker: PendingTransactionTracker,\n transactionId: string,\n ): void {\n const listeners = this.#boundListeners[transactionId];\n\n pendingTransactionTracker.hub.off(\n 'transaction-confirmed',\n listeners.onConfirmed,\n );\n pendingTransactionTracker.hub.off(\n 'transaction-failed',\n listeners.onFailedOrDropped,\n );\n pendingTransactionTracker.hub.off(\n 'transaction-dropped',\n listeners.onFailedOrDropped,\n );\n\n delete this.#boundListeners[transactionId];\n }\n}\n"]}
@@ -9,6 +9,7 @@ const feature_flags_1 = require("./feature-flags.cjs");
9
9
  const validation_1 = require("./validation.cjs");
10
10
  const __1 = require("../index.cjs");
11
11
  const CollectPublishHook_1 = require("../hooks/CollectPublishHook.cjs");
12
+ const SequentialPublishBatchHook_1 = require("../hooks/SequentialPublishBatchHook.cjs");
12
13
  const logger_1 = require("../logger.cjs");
13
14
  const types_1 = require("../types.cjs");
14
15
  const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'batch');
@@ -71,7 +72,7 @@ async function isAtomicBatchSupported(request) {
71
72
  }
72
73
  exports.isAtomicBatchSupported = isAtomicBatchSupported;
73
74
  /**
74
- * Generate a tranasction batch ID.
75
+ * Generate a transaction batch ID.
75
76
  *
76
77
  * @returns A unique batch ID as a hexadecimal string.
77
78
  */
@@ -149,7 +150,9 @@ async function addTransactionBatchWith7702(request) {
149
150
  delegationMock: txParams.authorizationList?.[0]?.address,
150
151
  };
151
152
  log('Security request', securityRequest);
153
+ /* istanbul ignore next */
152
154
  validateSecurity(securityRequest, chainId).catch((error) => {
155
+ /* istanbul ignore next */
153
156
  log('Security validation failed', error);
154
157
  });
155
158
  }
@@ -180,13 +183,16 @@ async function addTransactionBatchWith7702(request) {
180
183
  * @returns The batch result object including the batch ID.
181
184
  */
182
185
  async function addTransactionBatchWithHook(request) {
183
- const { publishBatchHook, request: userRequest } = request;
186
+ const { publishBatchHook: requestPublishBatchHook, request: userRequest } = request;
184
187
  const { from, networkClientId, transactions: nestedTransactions, } = userRequest;
185
188
  log('Adding transaction batch using hook', userRequest);
186
- if (!publishBatchHook) {
187
- log('No publish batch hook provided');
188
- throw new Error('No publish batch hook provided');
189
- }
189
+ const sequentialPublishBatchHook = new SequentialPublishBatchHook_1.SequentialPublishBatchHook({
190
+ publishTransaction: request.publishTransaction,
191
+ getTransaction: request.getTransaction,
192
+ getEthQuery: request.getEthQuery,
193
+ getPendingTransactionTracker: request.getPendingTransactionTracker,
194
+ });
195
+ const publishBatchHook = requestPublishBatchHook ?? sequentialPublishBatchHook.getHook();
190
196
  const batchId = generateBatchId();
191
197
  const transactionCount = nestedTransactions.length;
192
198
  const collectHook = new CollectPublishHook_1.CollectPublishHook(transactionCount);
@@ -1 +1 @@
1
- {"version":3,"file":"batch.cjs","sourceRoot":"","sources":["../../src/utils/batch.ts"],"names":[],"mappings":";;;AACA,qDAAiD;AAEjD,2CAAiE;AACjE,+BAAiC;AAEjC,2CAKmB;AACnB,uDAIyB;AACzB,iDAAoD;AACpD,oCAMY;AACZ,wEAAiE;AACjE,0CAA0C;AAa1C,wCAKkB;AA0BlB,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,OAAO,CAAC,CAAC;AAE1C,QAAA,iCAAiC,GAC5C,oCAAoC,CAAC;AAEvC;;;;;GAKG;AACI,KAAK,UAAU,mBAAmB,CACvC,OAAmC;IAEnC,MAAM,EAAE,mBAAmB,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACzE,MAAM,SAAS,GAAG,IAAA,iCAAiB,EAAC,SAAS,CAAC,CAAC;IAE/C,IAAA,iCAAoB,EAAC;QACnB,gBAAgB,EAAE,mBAAmB,EAAE;QACvC,OAAO,EAAE,WAAW;QACpB,SAAS;KACV,CAAC,CAAC;IAEH,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC;IAEhC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAE3B,IAAI,OAAO,EAAE;QACX,OAAO,MAAM,2BAA2B,CAAC,OAAO,CAAC,CAAC;KACnD;IAED,OAAO,MAAM,2BAA2B,CAAC,OAAO,CAAC,CAAC;AACpD,CAAC;AArBD,kDAqBC;AAED;;;;;GAKG;AACI,KAAK,UAAU,sBAAsB,CAC1C,OAA8C;IAE9C,MAAM,EACJ,OAAO,EACP,QAAQ,EACR,WAAW,EACX,SAAS,EACT,gBAAgB,EAAE,SAAS,GAC5B,GAAG,OAAO,CAAC;IAEZ,IAAI,CAAC,SAAS,EAAE;QACd,MAAM,sBAAS,CAAC,QAAQ,CAAC,iCAAuB,CAAC,CAAC;KACnD;IAED,MAAM,YAAY,GAAG,IAAA,yCAAyB,EAAC,SAAS,CAAC,CAAC;IAE1D,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAC1C,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CACrD,CAAC;IAEF,MAAM,UAAU,GACd,MAAM,OAAO,CAAC,GAAG,CACf,gBAAgB,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACrC,IAAI;YACF,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;YAEtC,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,GACtC,MAAM,IAAA,oCAA0B,EAC9B,OAAO,EACP,OAAO,EACP,SAAS,EACT,SAAS,EACT,QAAQ,CACT,CAAC;YAEJ,MAAM,sBAAsB,GAAG,IAAA,gDAAgC,EAC7D,OAAO,EACP,SAAS,EACT,SAAS,CACV,CAAC;YAEF,OAAO;gBACL,OAAO;gBACP,iBAAiB;gBACjB,WAAW;gBACX,sBAAsB;aACvB,CAAC;SACH;QAAC,OAAO,KAAK,EAAE;YACd,GAAG,CAAC,qCAAqC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;YAC3D,OAAO,SAAS,CAAC;SAClB;IACH,CAAC,CAAC,CACH,CAAC;IAEJ,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAC/B,CAAC,MAAM,EAA+C,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CACzE,CAAC;IAEF,GAAG,CAAC,gCAAgC,EAAE,OAAO,CAAC,CAAC;IAE/C,OAAO,OAAO,CAAC;AACjB,CAAC;AA9DD,wDA8DC;AAED;;;;GAIG;AACH,SAAS,eAAe;IACtB,MAAM,QAAQ,GAAG,IAAA,SAAE,GAAE,CAAC;IACtB,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,IAAA,YAAK,EAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,OAAO,IAAA,kBAAU,EAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,wBAAwB,CACrC,OAAgC,EAChC,aAA4C,EAC5C,QAAkB;IAElB,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,CAAC;IAEjC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,4BAAwB,EAC7C,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,EACnB,QAAQ,CACT,CAAC;IAEF,OAAO;QACL,GAAG,MAAM;QACT,IAAI;KACL,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,2BAA2B,CACxC,OAAmC;IAEnC,MAAM,EACJ,cAAc,EACd,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,OAAO,EAAE,WAAW,GACrB,GAAG,OAAO,CAAC;IAEZ,MAAM,EACJ,OAAO,EAAE,eAAe,EACxB,IAAI,EACJ,eAAe,EACf,MAAM,EACN,eAAe,EACf,eAAe,EACf,YAAY,EACZ,gBAAgB,GACjB,GAAG,WAAW,CAAC;IAEhB,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IACtD,MAAM,gBAAgB,GAAG,IAAA,iCAAuB,EAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAErE,IAAI,CAAC,gBAAgB,EAAE;QACrB,GAAG,CAAC,iCAAiC,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,sBAAS,CAAC,QAAQ,CAAC,iCAAiC,CAAC,CAAC;KAC7D;IAED,IAAI,CAAC,gBAAgB,EAAE;QACrB,MAAM,sBAAS,CAAC,QAAQ,CAAC,iCAAuB,CAAC,CAAC;KACnD;IAED,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,MAAM,IAAA,oCAA0B,EACzE,IAAI,EACJ,OAAO,EACP,gBAAgB,EAChB,SAAS,EACT,QAAQ,CACT,CAAC;IAEF,GAAG,CAAC,SAAS,EAAE,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC,CAAC;IAEnD,IAAI,CAAC,WAAW,IAAI,iBAAiB,EAAE;QACrC,GAAG,CAAC,0CAA0C,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC;QACzE,MAAM,sBAAS,CAAC,QAAQ,CAAC,0CAA0C,CAAC,CAAC;KACtE;IAED,MAAM,kBAAkB,GAAG,MAAM,OAAO,CAAC,GAAG,CAC1C,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CACtB,wBAAwB,CAAC,WAAW,EAAE,EAAE,EAAE,QAAQ,CAAC,CACpD,CACF,CAAC;IAEF,MAAM,WAAW,GAAG,IAAA,yCAA+B,EAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAE9E,MAAM,QAAQ,GAAsB;QAClC,IAAI;QACJ,GAAG,WAAW;KACf,CAAC;IAEF,IAAI,CAAC,WAAW,EAAE;QAChB,MAAM,sBAAsB,GAAG,IAAA,gDAAgC,EAC7D,OAAO,EACP,SAAS,EACT,gBAAgB,CACjB,CAAC;QAEF,IAAI,CAAC,sBAAsB,EAAE;YAC3B,MAAM,sBAAS,CAAC,QAAQ,CAAC,yCAAiC,CAAC,CAAC;SAC7D;QAED,QAAQ,CAAC,IAAI,GAAG,+BAAuB,CAAC,OAAO,CAAC;QAChD,QAAQ,CAAC,iBAAiB,GAAG,CAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;KACpE;IAED,IAAI,gBAAgB,EAAE;QACpB,MAAM,eAAe,GAA4B;YAC/C,MAAM,EAAE,qBAAqB;YAC7B,MAAM,EAAE;gBACN;oBACE,GAAG,QAAQ;oBACX,iBAAiB,EAAE,SAAS;oBAC5B,IAAI,EAAE,+BAAuB,CAAC,SAAS;iBACxC;aACF;YACD,cAAc,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO;SACzD,CAAC;QAEF,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;QAEzC,gBAAgB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACzD,GAAG,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;KACJ;IAED,GAAG,CAAC,0BAA0B,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;IAE3D,MAAM,OAAO,GAAG,eAAe,IAAI,eAAe,EAAE,CAAC;IAErD,MAAM,qBAAqB,GAAG,eAAe;QAC3C,CAAC,CAAE,EAAE,eAAe,EAA4B;QAChD,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE;QAChD,OAAO;QACP,kBAAkB;QAClB,eAAe;QACf,MAAM;QACN,eAAe;QACf,qBAAqB;QACrB,IAAI,EAAE,uBAAe,CAAC,KAAK;KAC5B,CAAC,CAAC;IAEH,4CAA4C;IAC5C,MAAM,MAAM,CAAC;IAEb,OAAO;QACL,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,2BAA2B,CACxC,OAAmC;IAEnC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAE3D,MAAM,EACJ,IAAI,EACJ,eAAe,EACf,YAAY,EAAE,kBAAkB,GACjC,GAAG,WAAW,CAAC;IAEhB,GAAG,CAAC,qCAAqC,EAAE,WAAW,CAAC,CAAC;IAExD,IAAI,CAAC,gBAAgB,EAAE;QACrB,GAAG,CAAC,gCAAgC,CAAC,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;KACnD;IAED,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;IAClC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,MAAM,CAAC;IACnD,MAAM,WAAW,GAAG,IAAI,uCAAkB,CAAC,gBAAgB,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;IAC1C,MAAM,gBAAgB,GAAoD,EAAE,CAAC;IAE7E,IAAI;QACF,KAAK,MAAM,iBAAiB,IAAI,kBAAkB,EAAE;YAClD,MAAM,eAAe,GAAG,MAAM,0BAA0B,CACtD,OAAO,EACP,iBAAiB,EACjB,WAAW,EACX,OAAO,CACR,CAAC;YAEF,gBAAgB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;SACxC;QAED,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAEzD,MAAM,YAAY,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACjE,GAAG,WAAW;YACd,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC;SACpC,CAAC,CAAC,CAAC;QAEJ,GAAG,CAAC,4BAA4B,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;QAE3E,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;YACpC,IAAI;YACJ,eAAe;YACf,YAAY;SACb,CAAC,CAAC;QAEH,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;QAEzC,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;SAC/D;QAED,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAC1C,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,eAAe,CACzC,CAAC;QAEF,WAAW,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAEvC,GAAG,CAAC,uCAAuC,EAAE,iBAAiB,CAAC,CAAC;QAEhE,OAAO;YACL,OAAO;SACR,CAAC;KACH;IAAC,OAAO,KAAK,EAAE;QACd,GAAG,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAExC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAEzB,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,0BAA0B,CACvC,OAAY,EACZ,iBAAgD,EAChD,WAAwB,EACxB,OAAmC;IAEnC,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC;IAE1D,MAAM,EACJ,cAAc,EACd,cAAc,EACd,OAAO,EAAE,WAAW,EACpB,iBAAiB,GAClB,GAAG,OAAO,CAAC;IAEZ,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,WAAW,CAAC;IAE9C,IAAI,mBAAmB,EAAE;QACvB,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,mBAAmB,CAAC;QACjE,MAAM,eAAe,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;QAE3C,iBAAiB,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,EAAE,CAAC,gBAAgB,EAAE,EAAE;YAC5D,gBAAgB,CAAC,OAAO,GAAG,OAAO,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,WAAW,CAAC,eAAe,EAAE,iBAAiB,CAAC;aAC5C,IAAI,CAAC,SAAS,CAAC;aACf,KAAK,CAAC,GAAG,EAAE;YACV,sBAAsB;QACxB,CAAC,CAAC,CAAC;QAEL,GAAG,CAAC,0CAA0C,EAAE;YAC9C,EAAE;YACF,MAAM;SACP,CAAC,CAAC;QAEH,OAAO;YACL,EAAE;YACF,MAAM;SACP,CAAC;KACH;IAED,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,cAAc,CAC9C;QACE,GAAG,MAAM;QACT,IAAI;KACL,EACD;QACE,OAAO;QACP,gBAAgB,EAAE,IAAI;QACtB,eAAe;QACf,WAAW;QACX,eAAe,EAAE,KAAK;KACvB,CACF,CAAC;IAEF,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAuB,CAAC;IAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAsB,CAAC;IAC5C,MAAM,YAAY,GAAG,QAAQ,CAAC,YAA+B,CAAC;IAC9D,MAAM,oBAAoB,GAAG,QAAQ,CAAC,oBAAuC,CAAC;IAC9E,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAqB,CAAC;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAwB,CAAC;IAEhD,MAAM,SAAS,GAA2B;QACxC,IAAI;QACJ,GAAG;QACH,YAAY;QACZ,oBAAoB;QACpB,EAAE;QACF,KAAK;KACN,CAAC;IAEF,GAAG,CAAC,qCAAqC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAEtE,OAAO;QACL,EAAE;QACF,MAAM,EAAE,SAAS;KAClB,CAAC;AACJ,CAAC","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 ERROR_MESSGE_PUBLIC_KEY,\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 IsAtomicBatchSupportedResult,\n IsAtomicBatchSupportedResultEntry,\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 IsAtomicBatchSupportedRequestInternal = {\n address: Hex;\n chainIds?: Hex[];\n getEthQuery: (chainId: Hex) => EthQuery;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n};\n\nconst log = createModuleLogger(projectLogger, 'batch');\n\nexport const ERROR_MESSAGE_NO_UPGRADE_CONTRACT =\n 'Upgrade contract address not found';\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 { getInternalAccounts, messenger, request: userRequest } = request;\n const sizeLimit = getBatchSizeLimit(messenger);\n\n validateBatchRequest({\n internalAccounts: getInternalAccounts(),\n request: userRequest,\n sizeLimit,\n });\n\n const { useHook } = userRequest;\n\n log('Adding', userRequest);\n\n if (useHook) {\n return await addTransactionBatchWithHook(request);\n }\n\n return await addTransactionBatchWith7702(request);\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: IsAtomicBatchSupportedRequestInternal,\n): Promise<IsAtomicBatchSupportedResult> {\n const {\n address,\n chainIds,\n getEthQuery,\n messenger,\n publicKeyEIP7702: publicKey,\n } = request;\n\n if (!publicKey) {\n throw rpcErrors.internal(ERROR_MESSGE_PUBLIC_KEY);\n }\n\n const chainIds7702 = getEIP7702SupportedChains(messenger);\n\n const filteredChainIds = chainIds7702.filter(\n (chainId) => !chainIds || chainIds.includes(chainId),\n );\n\n const resultsRaw: (IsAtomicBatchSupportedResultEntry | undefined)[] =\n await Promise.all(\n filteredChainIds.map(async (chainId) => {\n try {\n const ethQuery = getEthQuery(chainId);\n\n const { isSupported, delegationAddress } =\n await isAccountUpgradedToEIP7702(\n address,\n chainId,\n publicKey,\n messenger,\n ethQuery,\n );\n\n const upgradeContractAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKey,\n );\n\n return {\n chainId,\n delegationAddress,\n isSupported,\n upgradeContractAddress,\n };\n } catch (error) {\n log('Error checking atomic batch support', chainId, error);\n return undefined;\n }\n }),\n );\n\n const results = resultsRaw.filter(\n (result): result is IsAtomicBatchSupportedResultEntry => Boolean(result),\n );\n\n log('Atomic batch supported results', results);\n\n return results;\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 an EIP-7702 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 */\nasync function addTransactionBatchWith7702(\n request: AddTransactionBatchRequest,\n) {\n const {\n addTransaction,\n getChainId,\n messenger,\n publicKeyEIP7702,\n request: userRequest,\n } = request;\n\n const {\n batchId: batchIdOverride,\n from,\n networkClientId,\n origin,\n requireApproval,\n securityAlertId,\n transactions,\n validateSecurity,\n } = 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(ERROR_MESSGE_PUBLIC_KEY);\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(ERROR_MESSAGE_NO_UPGRADE_CONTRACT);\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 origin,\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 * 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
+ {"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 ERROR_MESSGE_PUBLIC_KEY,\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 type { PendingTransactionTracker } from '../helpers/PendingTransactionTracker';\nimport { CollectPublishHook } from '../hooks/CollectPublishHook';\nimport { SequentialPublishBatchHook } from '../hooks/SequentialPublishBatchHook';\nimport { projectLogger } from '../logger';\nimport type {\n NestedTransactionMetadata,\n SecurityAlertResponse,\n TransactionBatchSingleRequest,\n PublishBatchHook,\n PublishBatchHookTransaction,\n PublishHook,\n TransactionBatchRequest,\n ValidateSecurityRequest,\n IsAtomicBatchSupportedResult,\n IsAtomicBatchSupportedResultEntry,\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 publishTransaction: (\n _ethQuery: EthQuery,\n transactionMeta: TransactionMeta,\n ) => Promise<Hex>;\n getPendingTransactionTracker: (\n networkClientId: string,\n ) => PendingTransactionTracker;\n};\n\ntype IsAtomicBatchSupportedRequestInternal = {\n address: Hex;\n chainIds?: Hex[];\n getEthQuery: (chainId: Hex) => EthQuery;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n};\n\nconst log = createModuleLogger(projectLogger, 'batch');\n\nexport const ERROR_MESSAGE_NO_UPGRADE_CONTRACT =\n 'Upgrade contract address not found';\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 { getInternalAccounts, messenger, request: userRequest } = request;\n const sizeLimit = getBatchSizeLimit(messenger);\n\n validateBatchRequest({\n internalAccounts: getInternalAccounts(),\n request: userRequest,\n sizeLimit,\n });\n\n const { useHook } = userRequest;\n\n log('Adding', userRequest);\n\n if (useHook) {\n return await addTransactionBatchWithHook(request);\n }\n\n return await addTransactionBatchWith7702(request);\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: IsAtomicBatchSupportedRequestInternal,\n): Promise<IsAtomicBatchSupportedResult> {\n const {\n address,\n chainIds,\n getEthQuery,\n messenger,\n publicKeyEIP7702: publicKey,\n } = request;\n\n if (!publicKey) {\n throw rpcErrors.internal(ERROR_MESSGE_PUBLIC_KEY);\n }\n\n const chainIds7702 = getEIP7702SupportedChains(messenger);\n\n const filteredChainIds = chainIds7702.filter(\n (chainId) => !chainIds || chainIds.includes(chainId),\n );\n\n const resultsRaw: (IsAtomicBatchSupportedResultEntry | undefined)[] =\n await Promise.all(\n filteredChainIds.map(async (chainId) => {\n try {\n const ethQuery = getEthQuery(chainId);\n\n const { isSupported, delegationAddress } =\n await isAccountUpgradedToEIP7702(\n address,\n chainId,\n publicKey,\n messenger,\n ethQuery,\n );\n\n const upgradeContractAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKey,\n );\n\n return {\n chainId,\n delegationAddress,\n isSupported,\n upgradeContractAddress,\n };\n } catch (error) {\n log('Error checking atomic batch support', chainId, error);\n return undefined;\n }\n }),\n );\n\n const results = resultsRaw.filter(\n (result): result is IsAtomicBatchSupportedResultEntry => Boolean(result),\n );\n\n log('Atomic batch supported results', results);\n\n return results;\n}\n\n/**\n * Generate a transaction 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 an EIP-7702 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 */\nasync function addTransactionBatchWith7702(\n request: AddTransactionBatchRequest,\n) {\n const {\n addTransaction,\n getChainId,\n messenger,\n publicKeyEIP7702,\n request: userRequest,\n } = request;\n\n const {\n batchId: batchIdOverride,\n from,\n networkClientId,\n origin,\n requireApproval,\n securityAlertId,\n transactions,\n validateSecurity,\n } = 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(ERROR_MESSGE_PUBLIC_KEY);\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(ERROR_MESSAGE_NO_UPGRADE_CONTRACT);\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 /* istanbul ignore next */\n validateSecurity(securityRequest, chainId).catch((error) => {\n /* istanbul ignore next */\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 origin,\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 * 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: requestPublishBatchHook, request: userRequest } =\n request;\n\n const {\n from,\n networkClientId,\n transactions: nestedTransactions,\n } = userRequest;\n\n log('Adding transaction batch using hook', userRequest);\n\n const sequentialPublishBatchHook = new SequentialPublishBatchHook({\n publishTransaction: request.publishTransaction,\n getTransaction: request.getTransaction,\n getEthQuery: request.getEthQuery,\n getPendingTransactionTracker: request.getPendingTransactionTracker,\n });\n\n const publishBatchHook =\n requestPublishBatchHook ?? sequentialPublishBatchHook.getHook();\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,6 +1,7 @@
1
1
  import type EthQuery from "@metamask/eth-query";
2
2
  import type { Hex } from "@metamask/utils";
3
3
  import { type TransactionController, type TransactionControllerMessenger, type TransactionMeta } from "../index.cjs";
4
+ import type { PendingTransactionTracker } from "../helpers/PendingTransactionTracker.cjs";
4
5
  import type { PublishBatchHook, TransactionBatchRequest, IsAtomicBatchSupportedResult } from "../types.cjs";
5
6
  import { type TransactionBatchResult } from "../types.cjs";
6
7
  type AddTransactionBatchRequest = {
@@ -16,6 +17,8 @@ type AddTransactionBatchRequest = {
16
17
  updateTransaction: (options: {
17
18
  transactionId: string;
18
19
  }, callback: (transactionMeta: TransactionMeta) => void) => void;
20
+ publishTransaction: (_ethQuery: EthQuery, transactionMeta: TransactionMeta) => Promise<Hex>;
21
+ getPendingTransactionTracker: (networkClientId: string) => PendingTransactionTracker;
19
22
  };
20
23
  type IsAtomicBatchSupportedRequestInternal = {
21
24
  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;AAgB3C,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,eAAe,EACrB,qBAAW;AAGZ,OAAO,KAAK,EAIV,gBAAgB,EAGhB,uBAAuB,EAEvB,4BAA4B,EAE7B,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,qCAAqC,GAAG;IAC3C,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF,eAAO,MAAM,iCAAiC,uCACR,CAAC;AAEvC;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAmBjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,4BAA4B,CAAC,CA4DvC"}
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;AAgB3C,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,eAAe,EACrB,qBAAW;AACZ,OAAO,KAAK,EAAE,yBAAyB,EAAE,iDAA6C;AAItF,OAAO,KAAK,EAIV,gBAAgB,EAGhB,uBAAuB,EAEvB,4BAA4B,EAE7B,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;IACV,kBAAkB,EAAE,CAClB,SAAS,EAAE,QAAQ,EACnB,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,4BAA4B,EAAE,CAC5B,eAAe,EAAE,MAAM,KACpB,yBAAyB,CAAC;CAChC,CAAC;AAEF,KAAK,qCAAqC,GAAG;IAC3C,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF,eAAO,MAAM,iCAAiC,uCACR,CAAC;AAEvC;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAmBjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,4BAA4B,CAAC,CA4DvC"}
@@ -1,6 +1,7 @@
1
1
  import type EthQuery from "@metamask/eth-query";
2
2
  import type { Hex } from "@metamask/utils";
3
3
  import { type TransactionController, type TransactionControllerMessenger, type TransactionMeta } from "../index.mjs";
4
+ import type { PendingTransactionTracker } from "../helpers/PendingTransactionTracker.mjs";
4
5
  import type { PublishBatchHook, TransactionBatchRequest, IsAtomicBatchSupportedResult } from "../types.mjs";
5
6
  import { type TransactionBatchResult } from "../types.mjs";
6
7
  type AddTransactionBatchRequest = {
@@ -16,6 +17,8 @@ type AddTransactionBatchRequest = {
16
17
  updateTransaction: (options: {
17
18
  transactionId: string;
18
19
  }, callback: (transactionMeta: TransactionMeta) => void) => void;
20
+ publishTransaction: (_ethQuery: EthQuery, transactionMeta: TransactionMeta) => Promise<Hex>;
21
+ getPendingTransactionTracker: (networkClientId: string) => PendingTransactionTracker;
19
22
  };
20
23
  type IsAtomicBatchSupportedRequestInternal = {
21
24
  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;AAgB3C,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,eAAe,EACrB,qBAAW;AAGZ,OAAO,KAAK,EAIV,gBAAgB,EAGhB,uBAAuB,EAEvB,4BAA4B,EAE7B,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,qCAAqC,GAAG;IAC3C,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF,eAAO,MAAM,iCAAiC,uCACR,CAAC;AAEvC;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAmBjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,4BAA4B,CAAC,CA4DvC"}
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;AAgB3C,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,eAAe,EACrB,qBAAW;AACZ,OAAO,KAAK,EAAE,yBAAyB,EAAE,iDAA6C;AAItF,OAAO,KAAK,EAIV,gBAAgB,EAGhB,uBAAuB,EAEvB,4BAA4B,EAE7B,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;IACV,kBAAkB,EAAE,CAClB,SAAS,EAAE,QAAQ,EACnB,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,4BAA4B,EAAE,CAC5B,eAAe,EAAE,MAAM,KACpB,yBAAyB,CAAC;CAChC,CAAC;AAEF,KAAK,qCAAqC,GAAG;IAC3C,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;IACxC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB,CAAC;AAIF,eAAO,MAAM,iCAAiC,uCACR,CAAC;AAEvC;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAmBjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,4BAA4B,CAAC,CA4DvC"}
@@ -6,6 +6,7 @@ import { getBatchSizeLimit, getEIP7702SupportedChains, getEIP7702UpgradeContract
6
6
  import { validateBatchRequest } from "./validation.mjs";
7
7
  import { determineTransactionType } from "../index.mjs";
8
8
  import { CollectPublishHook } from "../hooks/CollectPublishHook.mjs";
9
+ import { SequentialPublishBatchHook } from "../hooks/SequentialPublishBatchHook.mjs";
9
10
  import { projectLogger } from "../logger.mjs";
10
11
  import { TransactionEnvelopeType, TransactionType } from "../types.mjs";
11
12
  const log = createModuleLogger(projectLogger, 'batch');
@@ -66,7 +67,7 @@ export async function isAtomicBatchSupported(request) {
66
67
  return results;
67
68
  }
68
69
  /**
69
- * Generate a tranasction batch ID.
70
+ * Generate a transaction batch ID.
70
71
  *
71
72
  * @returns A unique batch ID as a hexadecimal string.
72
73
  */
@@ -144,7 +145,9 @@ async function addTransactionBatchWith7702(request) {
144
145
  delegationMock: txParams.authorizationList?.[0]?.address,
145
146
  };
146
147
  log('Security request', securityRequest);
148
+ /* istanbul ignore next */
147
149
  validateSecurity(securityRequest, chainId).catch((error) => {
150
+ /* istanbul ignore next */
148
151
  log('Security validation failed', error);
149
152
  });
150
153
  }
@@ -175,13 +178,16 @@ async function addTransactionBatchWith7702(request) {
175
178
  * @returns The batch result object including the batch ID.
176
179
  */
177
180
  async function addTransactionBatchWithHook(request) {
178
- const { publishBatchHook, request: userRequest } = request;
181
+ const { publishBatchHook: requestPublishBatchHook, request: userRequest } = request;
179
182
  const { from, networkClientId, transactions: nestedTransactions, } = userRequest;
180
183
  log('Adding transaction batch using hook', userRequest);
181
- if (!publishBatchHook) {
182
- log('No publish batch hook provided');
183
- throw new Error('No publish batch hook provided');
184
- }
184
+ const sequentialPublishBatchHook = new SequentialPublishBatchHook({
185
+ publishTransaction: request.publishTransaction,
186
+ getTransaction: request.getTransaction,
187
+ getEthQuery: request.getEthQuery,
188
+ getPendingTransactionTracker: request.getPendingTransactionTracker,
189
+ });
190
+ const publishBatchHook = requestPublishBatchHook ?? sequentialPublishBatchHook.getHook();
185
191
  const batchId = generateBatchId();
186
192
  const transactionCount = nestedTransactions.length;
187
193
  const collectHook = new CollectPublishHook(transactionCount);