@pimlico/alto 0.0.0-main.20250203T212650 → 0.0.0-main.20250205T142138
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/cli/config/bundler.d.ts +0 -6
- package/esm/cli/config/bundler.js +0 -1
- package/esm/cli/config/bundler.js.map +1 -1
- package/esm/cli/config/options.js +0 -6
- package/esm/cli/config/options.js.map +1 -1
- package/esm/cli/setupServer.js +5 -5
- package/esm/cli/setupServer.js.map +1 -1
- package/esm/executor/executor.d.ts +34 -44
- package/esm/executor/executor.js +103 -463
- package/esm/executor/executor.js.map +1 -1
- package/esm/executor/executorManager.d.ts +20 -10
- package/esm/executor/executorManager.js +371 -310
- package/esm/executor/executorManager.js.map +1 -1
- package/esm/executor/filterOpsAndEStimateGas.d.ts +28 -0
- package/esm/executor/filterOpsAndEStimateGas.js +191 -0
- package/esm/executor/filterOpsAndEStimateGas.js.map +1 -0
- package/esm/executor/senderManager.d.ts +2 -0
- package/esm/executor/senderManager.js +32 -0
- package/esm/executor/senderManager.js.map +1 -1
- package/esm/executor/utils.d.ts +21 -20
- package/esm/executor/utils.js +46 -185
- package/esm/executor/utils.js.map +1 -1
- package/esm/handlers/eventManager.d.ts +4 -1
- package/esm/handlers/eventManager.js +10 -8
- package/esm/handlers/eventManager.js.map +1 -1
- package/esm/mempool/mempool.d.ts +15 -11
- package/esm/mempool/mempool.js +207 -176
- package/esm/mempool/mempool.js.map +1 -1
- package/esm/mempool/store.d.ts +7 -7
- package/esm/mempool/store.js +13 -12
- package/esm/mempool/store.js.map +1 -1
- package/esm/rpc/nonceQueuer.js +2 -2
- package/esm/rpc/nonceQueuer.js.map +1 -1
- package/esm/rpc/rpcHandler.js +27 -31
- package/esm/rpc/rpcHandler.js.map +1 -1
- package/esm/types/mempool.d.ts +40 -41
- package/esm/types/mempool.js.map +1 -1
- package/esm/types/schemas.d.ts +0 -4
- package/esm/types/schemas.js.map +1 -1
- package/esm/utils/userop.d.ts +8 -3
- package/esm/utils/userop.js +5 -3
- package/esm/utils/userop.js.map +1 -1
- package/lib/cli/config/bundler.d.ts +0 -6
- package/lib/cli/config/bundler.js +0 -1
- package/lib/cli/config/bundler.js.map +1 -1
- package/lib/cli/config/options.js +0 -6
- package/lib/cli/config/options.js.map +1 -1
- package/lib/cli/setupServer.js +5 -5
- package/lib/cli/setupServer.js.map +1 -1
- package/lib/executor/executor.d.ts +34 -44
- package/lib/executor/executor.js +100 -460
- package/lib/executor/executor.js.map +1 -1
- package/lib/executor/executorManager.d.ts +20 -10
- package/lib/executor/executorManager.js +370 -309
- package/lib/executor/executorManager.js.map +1 -1
- package/lib/executor/filterOpsAndEStimateGas.d.ts +28 -0
- package/lib/executor/filterOpsAndEStimateGas.js +218 -0
- package/lib/executor/filterOpsAndEStimateGas.js.map +1 -0
- package/lib/executor/senderManager.d.ts +2 -0
- package/lib/executor/senderManager.js +32 -0
- package/lib/executor/senderManager.js.map +1 -1
- package/lib/executor/utils.d.ts +21 -20
- package/lib/executor/utils.js +49 -186
- package/lib/executor/utils.js.map +1 -1
- package/lib/handlers/eventManager.d.ts +4 -1
- package/lib/handlers/eventManager.js +10 -8
- package/lib/handlers/eventManager.js.map +1 -1
- package/lib/mempool/mempool.d.ts +15 -11
- package/lib/mempool/mempool.js +206 -175
- package/lib/mempool/mempool.js.map +1 -1
- package/lib/mempool/store.d.ts +7 -7
- package/lib/mempool/store.js +13 -12
- package/lib/mempool/store.js.map +1 -1
- package/lib/rpc/nonceQueuer.js +1 -1
- package/lib/rpc/nonceQueuer.js.map +1 -1
- package/lib/rpc/rpcHandler.js +26 -30
- package/lib/rpc/rpcHandler.js.map +1 -1
- package/lib/types/mempool.d.ts +40 -41
- package/lib/types/mempool.js.map +1 -1
- package/lib/types/schemas.d.ts +0 -4
- package/lib/types/schemas.js.map +1 -1
- package/lib/utils/userop.d.ts +8 -3
- package/lib/utils/userop.js +7 -5
- package/lib/utils/userop.js.map +1 -1
- package/package.json +1 -1
- package/esm/executor/types.d.ts +0 -25
- package/esm/executor/types.js +0 -2
- package/esm/executor/types.js.map +0 -1
- package/lib/executor/types.d.ts +0 -25
- package/lib/executor/types.js +0 -3
- package/lib/executor/types.js.map +0 -1
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { EntryPointV06Abi } from "../types/index.js";
|
|
2
2
|
import { getAAError, getBundleStatus, parseUserOperationReceipt, scaleBigIntByPercent } from "../utils/index.js";
|
|
3
|
-
import { TransactionReceiptNotFoundError, getAbiItem } from "viem";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { TransactionReceiptNotFoundError, getAbiItem, InsufficientFundsError, NonceTooLowError } from "viem";
|
|
4
|
+
import { BaseError } from "abitype";
|
|
5
|
+
import { getUserOpHashes } from "./utils.js";
|
|
6
|
+
function getTransactionsFromUserOperationEntries(submittedOps) {
|
|
7
|
+
const transactionInfos = submittedOps.map((userOpInfo) => userOpInfo.transactionInfo);
|
|
8
|
+
// Remove duplicates
|
|
9
|
+
return Array.from(new Set(transactionInfos));
|
|
8
10
|
}
|
|
9
11
|
const MIN_INTERVAL = 100; // 0.1 seconds (100ms)
|
|
10
12
|
const MAX_INTERVAL = 1000; // Capped at 1 second (1000ms)
|
|
11
13
|
const SCALE_FACTOR = 10; // Interval increases by 5ms per task per minute
|
|
12
14
|
const RPM_WINDOW = 60000; // 1 minute window in ms
|
|
13
15
|
export class ExecutorManager {
|
|
16
|
+
senderManager;
|
|
14
17
|
config;
|
|
15
18
|
executor;
|
|
16
19
|
mempool;
|
|
@@ -24,7 +27,7 @@ export class ExecutorManager {
|
|
|
24
27
|
eventManager;
|
|
25
28
|
opsCount = [];
|
|
26
29
|
bundlingMode;
|
|
27
|
-
constructor({ config, executor, mempool, monitor, reputationManager, metrics, gasPriceManager, eventManager }) {
|
|
30
|
+
constructor({ config, executor, mempool, monitor, reputationManager, metrics, gasPriceManager, eventManager, senderManager }) {
|
|
28
31
|
this.config = config;
|
|
29
32
|
this.reputationManager = reputationManager;
|
|
30
33
|
this.executor = executor;
|
|
@@ -36,6 +39,7 @@ export class ExecutorManager {
|
|
|
36
39
|
this.metrics = metrics;
|
|
37
40
|
this.gasPriceManager = gasPriceManager;
|
|
38
41
|
this.eventManager = eventManager;
|
|
42
|
+
this.senderManager = senderManager;
|
|
39
43
|
this.bundlingMode = this.config.bundleMode;
|
|
40
44
|
if (this.bundlingMode === "auto") {
|
|
41
45
|
this.autoScalingBundling();
|
|
@@ -53,12 +57,18 @@ export class ExecutorManager {
|
|
|
53
57
|
async autoScalingBundling() {
|
|
54
58
|
const now = Date.now();
|
|
55
59
|
this.opsCount = this.opsCount.filter((timestamp) => now - timestamp < RPM_WINDOW);
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
58
|
-
const opsCount =
|
|
60
|
+
const bundles = await this.mempool.getBundles();
|
|
61
|
+
if (bundles.length > 0) {
|
|
62
|
+
const opsCount = bundles
|
|
63
|
+
.map(({ userOps }) => userOps.length)
|
|
64
|
+
.reduce((a, b) => a + b);
|
|
65
|
+
// Add timestamps for each task
|
|
59
66
|
const timestamp = Date.now();
|
|
60
|
-
this.opsCount.push(...Array(opsCount).fill(timestamp));
|
|
61
|
-
|
|
67
|
+
this.opsCount.push(...Array(opsCount).fill(timestamp));
|
|
68
|
+
// Send bundles to executor
|
|
69
|
+
await Promise.all(bundles.map(async (bundle) => {
|
|
70
|
+
await this.sendBundleToExecutor(bundle);
|
|
71
|
+
}));
|
|
62
72
|
}
|
|
63
73
|
const rpm = this.opsCount.length;
|
|
64
74
|
// Calculate next interval with linear scaling
|
|
@@ -69,145 +79,106 @@ export class ExecutorManager {
|
|
|
69
79
|
setTimeout(this.autoScalingBundling.bind(this), nextInterval);
|
|
70
80
|
}
|
|
71
81
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
opsToBundle.push(ops);
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (opsToBundle.length === 0) {
|
|
84
|
-
return [];
|
|
85
|
-
}
|
|
86
|
-
return opsToBundle;
|
|
87
|
-
}
|
|
88
|
-
async bundleNow() {
|
|
89
|
-
const ops = await this.mempool.process(this.config.maxGasPerBundle, 1);
|
|
90
|
-
if (ops.length === 0) {
|
|
82
|
+
// Debug endpoint
|
|
83
|
+
async sendBundleNow() {
|
|
84
|
+
const bundles = await this.mempool.getBundles(1);
|
|
85
|
+
const bundle = bundles[0];
|
|
86
|
+
if (bundle.userOps.length === 0) {
|
|
91
87
|
throw new Error("no ops to bundle");
|
|
92
88
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
opEntryPointMap.set(op.entryPoint, []);
|
|
97
|
-
}
|
|
98
|
-
opEntryPointMap.get(op.entryPoint)?.push(op.userOperation);
|
|
99
|
-
}
|
|
100
|
-
const txHashes = [];
|
|
101
|
-
await Promise.all(this.config.entrypoints.map(async (entryPoint) => {
|
|
102
|
-
const ops = opEntryPointMap.get(entryPoint);
|
|
103
|
-
if (ops) {
|
|
104
|
-
const txHash = await this.sendToExecutor(entryPoint, ops);
|
|
105
|
-
if (!txHash) {
|
|
106
|
-
throw new Error("no tx hash");
|
|
107
|
-
}
|
|
108
|
-
txHashes.push(txHash);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
this.logger.warn({ entryPoint }, "no user operations for entry point");
|
|
112
|
-
}
|
|
113
|
-
}));
|
|
114
|
-
return txHashes;
|
|
115
|
-
}
|
|
116
|
-
async sendToExecutor(entryPoint, mempoolOps) {
|
|
117
|
-
const ops = mempoolOps.map((op) => op);
|
|
118
|
-
const bundles = [];
|
|
119
|
-
if (ops.length > 0) {
|
|
120
|
-
bundles.push(await this.executor.bundle(entryPoint, ops));
|
|
121
|
-
}
|
|
122
|
-
for (const bundle of bundles) {
|
|
123
|
-
const isBundleSuccess = bundle.every((result) => result.status === "success");
|
|
124
|
-
const isBundleResubmit = bundle.every((result) => result.status === "resubmit");
|
|
125
|
-
const isBundleFailed = bundle.every((result) => result.status === "failure");
|
|
126
|
-
if (isBundleSuccess) {
|
|
127
|
-
this.metrics.bundlesSubmitted
|
|
128
|
-
.labels({ status: "success" })
|
|
129
|
-
.inc();
|
|
130
|
-
}
|
|
131
|
-
if (isBundleResubmit) {
|
|
132
|
-
this.metrics.bundlesSubmitted
|
|
133
|
-
.labels({ status: "resubmit" })
|
|
134
|
-
.inc();
|
|
135
|
-
}
|
|
136
|
-
if (isBundleFailed) {
|
|
137
|
-
this.metrics.bundlesSubmitted.labels({ status: "failed" }).inc();
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
const results = bundles.flat();
|
|
141
|
-
const filteredOutOps = mempoolOps.length - results.length;
|
|
142
|
-
if (filteredOutOps > 0) {
|
|
143
|
-
this.logger.debug({ filteredOutOps }, "user operations filtered out");
|
|
144
|
-
this.metrics.userOperationsSubmitted
|
|
145
|
-
.labels({ status: "filtered" })
|
|
146
|
-
.inc(filteredOutOps);
|
|
147
|
-
}
|
|
148
|
-
let txHash = undefined;
|
|
149
|
-
for (const result of results) {
|
|
150
|
-
if (result.status === "success") {
|
|
151
|
-
const res = result.value;
|
|
152
|
-
this.mempool.markSubmitted(res.userOperation.userOperationHash, res.transactionInfo);
|
|
153
|
-
this.monitor.setUserOperationStatus(res.userOperation.userOperationHash, {
|
|
154
|
-
status: "submitted",
|
|
155
|
-
transactionHash: res.transactionInfo.transactionHash
|
|
156
|
-
});
|
|
157
|
-
txHash = res.transactionInfo.transactionHash;
|
|
158
|
-
this.startWatchingBlocks(this.handleBlock.bind(this));
|
|
159
|
-
this.metrics.userOperationsSubmitted
|
|
160
|
-
.labels({ status: "success" })
|
|
161
|
-
.inc();
|
|
162
|
-
}
|
|
163
|
-
if (result.status === "failure") {
|
|
164
|
-
const { userOpHash, reason } = result.error;
|
|
165
|
-
this.mempool.removeProcessing(userOpHash);
|
|
166
|
-
this.eventManager.emitDropped(userOpHash, reason, getAAError(reason));
|
|
167
|
-
this.monitor.setUserOperationStatus(userOpHash, {
|
|
168
|
-
status: "rejected",
|
|
169
|
-
transactionHash: null
|
|
170
|
-
});
|
|
171
|
-
this.logger.warn({
|
|
172
|
-
userOperation: JSON.stringify(result.error.userOperation, (_k, v) => typeof v === "bigint" ? v.toString() : v),
|
|
173
|
-
userOpHash,
|
|
174
|
-
reason
|
|
175
|
-
}, "user operation rejected");
|
|
176
|
-
this.metrics.userOperationsSubmitted
|
|
177
|
-
.labels({ status: "failed" })
|
|
178
|
-
.inc();
|
|
179
|
-
}
|
|
180
|
-
if (result.status === "resubmit") {
|
|
181
|
-
this.logger.info({
|
|
182
|
-
userOpHash: result.info.userOpHash,
|
|
183
|
-
reason: result.info.reason
|
|
184
|
-
}, "resubmitting user operation");
|
|
185
|
-
this.mempool.removeProcessing(result.info.userOpHash);
|
|
186
|
-
this.mempool.add(result.info.userOperation, result.info.entryPoint);
|
|
187
|
-
this.metrics.userOperationsResubmitted.inc();
|
|
188
|
-
}
|
|
89
|
+
const txHash = await this.sendBundleToExecutor(bundle);
|
|
90
|
+
if (!txHash) {
|
|
91
|
+
throw new Error("no tx hash");
|
|
189
92
|
}
|
|
190
93
|
return txHash;
|
|
191
94
|
}
|
|
192
|
-
async
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
95
|
+
async sendBundleToExecutor(userOpBundle) {
|
|
96
|
+
const { entryPoint, userOps, version } = userOpBundle;
|
|
97
|
+
if (userOps.length === 0) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const wallet = await this.senderManager.getWallet();
|
|
101
|
+
const [gasPriceParams, nonce] = await Promise.all([
|
|
102
|
+
this.gasPriceManager.tryGetNetworkGasPrice(),
|
|
103
|
+
this.config.publicClient.getTransactionCount({
|
|
104
|
+
address: wallet.address,
|
|
105
|
+
blockTag: "latest"
|
|
106
|
+
})
|
|
107
|
+
]).catch((_) => {
|
|
108
|
+
return [];
|
|
109
|
+
});
|
|
110
|
+
if (!gasPriceParams || nonce === undefined) {
|
|
111
|
+
this.resubmitUserOperations(userOps, entryPoint, "Failed to get nonce and gas parameters for bundling");
|
|
112
|
+
// Free executor if failed to get initial params.
|
|
113
|
+
this.senderManager.markWalletProcessed(wallet);
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const bundleResult = await this.executor.bundle({
|
|
117
|
+
executor: wallet,
|
|
118
|
+
userOpBundle,
|
|
119
|
+
nonce,
|
|
120
|
+
gasPriceParams,
|
|
121
|
+
isReplacementTx: false
|
|
122
|
+
});
|
|
123
|
+
// Free wallet if no bundle was sent.
|
|
124
|
+
if (bundleResult.status !== "bundle_success") {
|
|
125
|
+
this.senderManager.markWalletProcessed(wallet);
|
|
126
|
+
}
|
|
127
|
+
// All ops failed simulation, drop them and return.
|
|
128
|
+
if (bundleResult.status === "all_ops_failed_simulation") {
|
|
129
|
+
const { rejectedUserOps } = bundleResult;
|
|
130
|
+
this.dropUserOps(rejectedUserOps);
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
// Unhandled error during simulation, drop all ops.
|
|
134
|
+
if (bundleResult.status === "unhandled_simulation_failure") {
|
|
135
|
+
const { rejectedUserOps } = bundleResult;
|
|
136
|
+
this.dropUserOps(rejectedUserOps);
|
|
137
|
+
this.metrics.bundlesSubmitted.labels({ status: "failed" }).inc();
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
// Resubmit if executor has insufficient funds.
|
|
141
|
+
if (bundleResult.status === "bundle_submission_failure" &&
|
|
142
|
+
bundleResult.reason instanceof InsufficientFundsError) {
|
|
143
|
+
const { reason, userOpsToBundle, rejectedUserOps } = bundleResult;
|
|
144
|
+
this.dropUserOps(rejectedUserOps);
|
|
145
|
+
this.resubmitUserOperations(userOpsToBundle, entryPoint, reason.name);
|
|
146
|
+
this.metrics.bundlesSubmitted.labels({ status: "resubmit" }).inc();
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
// Encountered unhandled error during bundle simulation.
|
|
150
|
+
if (bundleResult.status === "bundle_submission_failure") {
|
|
151
|
+
const { rejectedUserOps, userOpsToBundle, reason } = bundleResult;
|
|
152
|
+
this.dropUserOps(rejectedUserOps);
|
|
153
|
+
// NOTE: these ops passed validation, so we can try resubmitting them
|
|
154
|
+
this.resubmitUserOperations(userOpsToBundle, entryPoint, reason instanceof BaseError
|
|
155
|
+
? reason.name
|
|
156
|
+
: "Encountered unhandled error during bundle simulation");
|
|
157
|
+
this.metrics.bundlesSubmitted.labels({ status: "failed" }).inc();
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
if (bundleResult.status === "bundle_success") {
|
|
161
|
+
const { userOpsBundled, rejectedUserOps, transactionRequest, transactionHash } = bundleResult;
|
|
162
|
+
const transactionInfo = {
|
|
163
|
+
executor: wallet,
|
|
164
|
+
transactionHash,
|
|
165
|
+
transactionRequest,
|
|
166
|
+
bundle: {
|
|
167
|
+
entryPoint,
|
|
168
|
+
version,
|
|
169
|
+
userOps: userOpsBundled
|
|
170
|
+
},
|
|
171
|
+
previousTransactionHashes: [],
|
|
172
|
+
lastReplaced: Date.now(),
|
|
173
|
+
firstSubmitted: Date.now(),
|
|
174
|
+
timesPotentiallyIncluded: 0
|
|
175
|
+
};
|
|
176
|
+
this.markUserOperationsAsSubmitted(userOpsBundled, transactionInfo);
|
|
177
|
+
this.dropUserOps(rejectedUserOps);
|
|
178
|
+
this.metrics.bundlesSubmitted.labels({ status: "success" }).inc();
|
|
179
|
+
return transactionHash;
|
|
180
|
+
}
|
|
181
|
+
return undefined;
|
|
211
182
|
}
|
|
212
183
|
startWatchingBlocks(handleBlock) {
|
|
213
184
|
if (this.unWatch) {
|
|
@@ -215,18 +186,6 @@ export class ExecutorManager {
|
|
|
215
186
|
}
|
|
216
187
|
this.unWatch = this.config.publicClient.watchBlocks({
|
|
217
188
|
onBlock: handleBlock,
|
|
218
|
-
// onBlock: async (block) => {
|
|
219
|
-
// // Use an arrow function to ensure correct binding of `this`
|
|
220
|
-
// this.checkAndReplaceTransactions(block)
|
|
221
|
-
// .then(() => {
|
|
222
|
-
// this.logger.trace("block handled")
|
|
223
|
-
// // Handle the resolution of the promise here, if needed
|
|
224
|
-
// })
|
|
225
|
-
// .catch((error) => {
|
|
226
|
-
// // Handle any errors that occur during the execution of the promise
|
|
227
|
-
// this.logger.error({ error }, "error while handling block")
|
|
228
|
-
// })
|
|
229
|
-
// },
|
|
230
189
|
onError: (error) => {
|
|
231
190
|
this.logger.error({ error }, "error while watching blocks");
|
|
232
191
|
},
|
|
@@ -244,94 +203,71 @@ export class ExecutorManager {
|
|
|
244
203
|
}
|
|
245
204
|
}
|
|
246
205
|
// update the current status of the bundling transaction/s
|
|
247
|
-
async refreshTransactionStatus(
|
|
248
|
-
const { transactionHash:
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
...previousTransactionHashes
|
|
252
|
-
];
|
|
206
|
+
async refreshTransactionStatus(transactionInfo) {
|
|
207
|
+
const { transactionHash: currentTxhash, bundle, previousTransactionHashes } = transactionInfo;
|
|
208
|
+
const { userOps, entryPoint } = bundle;
|
|
209
|
+
const txHashesToCheck = [currentTxhash, ...previousTransactionHashes];
|
|
253
210
|
const transactionDetails = await Promise.all(txHashesToCheck.map(async (transactionHash) => ({
|
|
254
211
|
transactionHash,
|
|
255
|
-
...(await getBundleStatus(
|
|
212
|
+
...(await getBundleStatus({
|
|
213
|
+
transactionHash,
|
|
214
|
+
bundle: transactionInfo.bundle,
|
|
215
|
+
publicClient: this.config.publicClient,
|
|
216
|
+
logger: this.logger
|
|
217
|
+
}))
|
|
256
218
|
})));
|
|
257
219
|
// first check if bundling txs returns status "mined", if not, check for reverted
|
|
258
220
|
const mined = transactionDetails.find(({ bundlingStatus }) => bundlingStatus.status === "included");
|
|
259
221
|
const reverted = transactionDetails.find(({ bundlingStatus }) => bundlingStatus.status === "reverted");
|
|
260
222
|
const finalizedTransaction = mined ?? reverted;
|
|
261
223
|
if (!finalizedTransaction) {
|
|
262
|
-
for (const { userOperationHash } of opInfos) {
|
|
263
|
-
this.logger.trace({
|
|
264
|
-
userOperationHash,
|
|
265
|
-
currentTransactionHash
|
|
266
|
-
}, "user op still pending");
|
|
267
|
-
}
|
|
268
224
|
return;
|
|
269
225
|
}
|
|
270
226
|
const { bundlingStatus, transactionHash, blockNumber } = finalizedTransaction;
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
.labels({ status: bundlingStatus.status })
|
|
274
|
-
.inc(opInfos.length);
|
|
275
|
-
const { userOperationDetails } = bundlingStatus;
|
|
276
|
-
opInfos.map((opInfo) => {
|
|
277
|
-
const { userOperation, userOperationHash, entryPoint, firstSubmitted } = opInfo;
|
|
278
|
-
const opDetails = userOperationDetails[userOperationHash];
|
|
279
|
-
this.metrics.userOperationInclusionDuration.observe((Date.now() - firstSubmitted) / 1000);
|
|
280
|
-
this.mempool.removeSubmitted(userOperationHash);
|
|
281
|
-
this.reputationManager.updateUserOperationIncludedStatus(userOperation, entryPoint, opDetails.accountDeployed);
|
|
282
|
-
if (opDetails.status === "succesful") {
|
|
283
|
-
this.eventManager.emitIncludedOnChain(userOperationHash, transactionHash, blockNumber);
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
this.eventManager.emitExecutionRevertedOnChain(userOperationHash, transactionHash, opDetails.revertReason || "0x", blockNumber);
|
|
287
|
-
}
|
|
288
|
-
this.monitor.setUserOperationStatus(userOperationHash, {
|
|
289
|
-
status: "included",
|
|
290
|
-
transactionHash
|
|
291
|
-
});
|
|
292
|
-
this.logger.info({
|
|
293
|
-
userOperationHash,
|
|
294
|
-
transactionHash
|
|
295
|
-
}, "user op included");
|
|
296
|
-
});
|
|
297
|
-
this.executor.markWalletProcessed(transactionInfo.executor);
|
|
298
|
-
}
|
|
299
|
-
else if (bundlingStatus.status === "reverted" &&
|
|
300
|
-
bundlingStatus.isAA95) {
|
|
227
|
+
// TODO: there has to be a better way of solving onchain AA95 errors.
|
|
228
|
+
if (bundlingStatus.status === "reverted" && bundlingStatus.isAA95) {
|
|
301
229
|
// resubmit with more gas when bundler encounters AA95
|
|
302
230
|
transactionInfo.transactionRequest.gas = scaleBigIntByPercent(transactionInfo.transactionRequest.gas, this.config.aa95GasMultiplier);
|
|
303
231
|
transactionInfo.transactionRequest.nonce += 1;
|
|
304
232
|
await this.replaceTransaction(transactionInfo, "AA95");
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
// Free executor if tx landed onchain
|
|
236
|
+
if (bundlingStatus.status !== "not_found") {
|
|
237
|
+
this.senderManager.markWalletProcessed(transactionInfo.executor);
|
|
305
238
|
}
|
|
306
|
-
|
|
307
|
-
|
|
239
|
+
if (bundlingStatus.status === "included") {
|
|
240
|
+
const { userOperationDetails } = bundlingStatus;
|
|
241
|
+
this.markUserOpsIncluded(userOps, entryPoint, blockNumber, transactionHash, userOperationDetails);
|
|
242
|
+
}
|
|
243
|
+
if (bundlingStatus.status === "reverted") {
|
|
244
|
+
await Promise.all(userOps.map((userOpInfo) => {
|
|
245
|
+
const { userOpHash } = userOpInfo;
|
|
308
246
|
this.checkFrontrun({
|
|
309
|
-
|
|
247
|
+
userOpHash,
|
|
310
248
|
transactionHash,
|
|
311
249
|
blockNumber
|
|
312
250
|
});
|
|
313
251
|
}));
|
|
314
|
-
|
|
315
|
-
this.mempool.removeSubmitted(userOperationHash);
|
|
316
|
-
});
|
|
317
|
-
this.executor.markWalletProcessed(transactionInfo.executor);
|
|
252
|
+
this.removeSubmitted(userOps);
|
|
318
253
|
}
|
|
319
254
|
}
|
|
320
|
-
checkFrontrun({
|
|
255
|
+
checkFrontrun({ userOpHash, transactionHash, blockNumber }) {
|
|
321
256
|
const unwatch = this.config.publicClient.watchBlockNumber({
|
|
322
257
|
onBlockNumber: async (currentBlockNumber) => {
|
|
323
258
|
if (currentBlockNumber > blockNumber + 1n) {
|
|
324
|
-
const userOperationReceipt = await this.getUserOperationReceipt(
|
|
259
|
+
const userOperationReceipt = await this.getUserOperationReceipt(userOpHash);
|
|
325
260
|
if (userOperationReceipt) {
|
|
326
261
|
const transactionHash = userOperationReceipt.receipt.transactionHash;
|
|
327
262
|
const blockNumber = userOperationReceipt.receipt.blockNumber;
|
|
328
|
-
this.
|
|
263
|
+
this.mempool.removeSubmitted(userOpHash);
|
|
264
|
+
this.monitor.setUserOperationStatus(userOpHash, {
|
|
329
265
|
status: "included",
|
|
330
266
|
transactionHash
|
|
331
267
|
});
|
|
332
|
-
this.eventManager.emitFrontranOnChain(
|
|
268
|
+
this.eventManager.emitFrontranOnChain(userOpHash, transactionHash, blockNumber);
|
|
333
269
|
this.logger.info({
|
|
334
|
-
userOpHash
|
|
270
|
+
userOpHash,
|
|
335
271
|
transactionHash
|
|
336
272
|
}, "user op frontrun onchain");
|
|
337
273
|
this.metrics.userOperationsOnChain
|
|
@@ -339,13 +275,13 @@ export class ExecutorManager {
|
|
|
339
275
|
.inc(1);
|
|
340
276
|
}
|
|
341
277
|
else {
|
|
342
|
-
this.monitor.setUserOperationStatus(
|
|
343
|
-
status: "
|
|
278
|
+
this.monitor.setUserOperationStatus(userOpHash, {
|
|
279
|
+
status: "failed",
|
|
344
280
|
transactionHash
|
|
345
281
|
});
|
|
346
|
-
this.eventManager.emitFailedOnChain(
|
|
282
|
+
this.eventManager.emitFailedOnChain(userOpHash, transactionHash, blockNumber);
|
|
347
283
|
this.logger.info({
|
|
348
|
-
userOpHash
|
|
284
|
+
userOpHash,
|
|
349
285
|
transactionHash
|
|
350
286
|
}, "user op failed onchain");
|
|
351
287
|
this.metrics.userOperationsOnChain
|
|
@@ -448,28 +384,6 @@ export class ExecutorManager {
|
|
|
448
384
|
const userOperationReceipt = parseUserOperationReceipt(userOperationHash, receipt);
|
|
449
385
|
return userOperationReceipt;
|
|
450
386
|
}
|
|
451
|
-
async refreshUserOperationStatuses() {
|
|
452
|
-
const ops = this.mempool.dumpSubmittedOps();
|
|
453
|
-
const opEntryPointMap = new Map();
|
|
454
|
-
for (const op of ops) {
|
|
455
|
-
if (!opEntryPointMap.has(op.userOperation.entryPoint)) {
|
|
456
|
-
opEntryPointMap.set(op.userOperation.entryPoint, []);
|
|
457
|
-
}
|
|
458
|
-
opEntryPointMap.get(op.userOperation.entryPoint)?.push(op);
|
|
459
|
-
}
|
|
460
|
-
await Promise.all(this.config.entrypoints.map(async (entryPoint) => {
|
|
461
|
-
const ops = opEntryPointMap.get(entryPoint);
|
|
462
|
-
if (ops) {
|
|
463
|
-
const txs = getTransactionsFromUserOperationEntries(ops);
|
|
464
|
-
await Promise.all(txs.map(async (txInfo) => {
|
|
465
|
-
await this.refreshTransactionStatus(entryPoint, txInfo);
|
|
466
|
-
}));
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
this.logger.warn({ entryPoint }, "no user operations for entry point");
|
|
470
|
-
}
|
|
471
|
-
}));
|
|
472
|
-
}
|
|
473
387
|
async handleBlock(block) {
|
|
474
388
|
if (this.currentlyHandlingBlock) {
|
|
475
389
|
return;
|
|
@@ -483,101 +397,248 @@ export class ExecutorManager {
|
|
|
483
397
|
return;
|
|
484
398
|
}
|
|
485
399
|
// refresh op statuses
|
|
486
|
-
|
|
400
|
+
const ops = this.mempool.dumpSubmittedOps();
|
|
401
|
+
const txs = getTransactionsFromUserOperationEntries(ops);
|
|
402
|
+
await Promise.all(txs.map((txInfo) => this.refreshTransactionStatus(txInfo)));
|
|
487
403
|
// for all still not included check if needs to be replaced (based on gas price)
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
gasPriceParameters = {
|
|
495
|
-
maxFeePerGas: 0n,
|
|
496
|
-
maxPriorityFeePerGas: 0n
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
this.logger.trace({ gasPriceParameters }, "fetched gas price parameters");
|
|
404
|
+
const gasPriceParameters = await this.gasPriceManager
|
|
405
|
+
.tryGetNetworkGasPrice()
|
|
406
|
+
.catch(() => ({
|
|
407
|
+
maxFeePerGas: 0n,
|
|
408
|
+
maxPriorityFeePerGas: 0n
|
|
409
|
+
}));
|
|
500
410
|
const transactionInfos = getTransactionsFromUserOperationEntries(this.mempool.dumpSubmittedOps());
|
|
501
411
|
await Promise.all(transactionInfos.map(async (txInfo) => {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
412
|
+
const { transactionRequest } = txInfo;
|
|
413
|
+
const { maxFeePerGas, maxPriorityFeePerGas } = transactionRequest;
|
|
414
|
+
const isMaxFeeTooLow = maxFeePerGas < gasPriceParameters.maxFeePerGas;
|
|
415
|
+
const isPriorityFeeTooLow = maxPriorityFeePerGas <
|
|
416
|
+
gasPriceParameters.maxPriorityFeePerGas;
|
|
417
|
+
const isStuck = Date.now() - txInfo.lastReplaced >
|
|
418
|
+
this.config.resubmitStuckTimeout;
|
|
419
|
+
if (isMaxFeeTooLow || isPriorityFeeTooLow) {
|
|
420
|
+
await this.replaceTransaction(txInfo, "gas_price");
|
|
506
421
|
return;
|
|
507
422
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
// for any left check if enough time has passed, if so replace
|
|
511
|
-
const transactionInfos2 = getTransactionsFromUserOperationEntries(this.mempool.dumpSubmittedOps());
|
|
512
|
-
await Promise.all(transactionInfos2.map(async (txInfo) => {
|
|
513
|
-
if (Date.now() - txInfo.lastReplaced <
|
|
514
|
-
this.config.resubmitStuckTimeout) {
|
|
423
|
+
if (isStuck) {
|
|
424
|
+
await this.replaceTransaction(txInfo, "stuck");
|
|
515
425
|
return;
|
|
516
426
|
}
|
|
517
|
-
await this.replaceTransaction(txInfo, "stuck");
|
|
518
427
|
}));
|
|
519
428
|
this.currentlyHandlingBlock = false;
|
|
520
429
|
}
|
|
521
430
|
async replaceTransaction(txInfo, reason) {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}, "user operation rejected");
|
|
540
|
-
this.mempool.removeSubmitted(opInfo.userOperationHash);
|
|
431
|
+
// Setup vars
|
|
432
|
+
const { bundle, executor, transactionRequest, transactionHash: oldTxHash } = txInfo;
|
|
433
|
+
const { userOps } = bundle;
|
|
434
|
+
const gasPriceParameters = await this.gasPriceManager
|
|
435
|
+
.tryGetNetworkGasPrice()
|
|
436
|
+
.catch((_) => {
|
|
437
|
+
return undefined;
|
|
438
|
+
});
|
|
439
|
+
if (!gasPriceParameters) {
|
|
440
|
+
const rejectedUserOps = userOps.map((userOpInfo) => ({
|
|
441
|
+
...userOpInfo,
|
|
442
|
+
reason: "Failed to get network gas price during replacement"
|
|
443
|
+
}));
|
|
444
|
+
this.failedToReplaceTransaction({
|
|
445
|
+
rejectedUserOps,
|
|
446
|
+
oldTxHash,
|
|
447
|
+
reason: "Failed to get network gas price during replacement"
|
|
541
448
|
});
|
|
542
|
-
|
|
449
|
+
// Free executor if failed to get initial params.
|
|
450
|
+
this.senderManager.markWalletProcessed(txInfo.executor);
|
|
543
451
|
return;
|
|
544
452
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
453
|
+
const bundleResult = await this.executor.bundle({
|
|
454
|
+
executor: executor,
|
|
455
|
+
userOpBundle: bundle,
|
|
456
|
+
nonce: transactionRequest.nonce,
|
|
457
|
+
gasPriceParams: {
|
|
458
|
+
maxFeePerGas: scaleBigIntByPercent(gasPriceParameters.maxFeePerGas, 115n),
|
|
459
|
+
maxPriorityFeePerGas: scaleBigIntByPercent(gasPriceParameters.maxPriorityFeePerGas, 115n)
|
|
460
|
+
},
|
|
461
|
+
gasLimitSuggestion: transactionRequest.gas,
|
|
462
|
+
isReplacementTx: true
|
|
463
|
+
});
|
|
464
|
+
// Free wallet and return if potentially included too many times.
|
|
465
|
+
if (txInfo.timesPotentiallyIncluded >= 3) {
|
|
548
466
|
if (txInfo.timesPotentiallyIncluded >= 3) {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
467
|
+
this.removeSubmitted(bundle.userOps);
|
|
468
|
+
this.logger.warn({
|
|
469
|
+
oldTxHash,
|
|
470
|
+
userOps: getUserOpHashes(bundleResult.rejectedUserOps)
|
|
471
|
+
}, "transaction potentially already included too many times, removing");
|
|
554
472
|
}
|
|
473
|
+
this.senderManager.markWalletProcessed(txInfo.executor);
|
|
555
474
|
return;
|
|
556
475
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
.
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
476
|
+
// Free wallet if no bundle was sent or potentially included.
|
|
477
|
+
if (bundleResult.status !== "bundle_success") {
|
|
478
|
+
this.senderManager.markWalletProcessed(txInfo.executor);
|
|
479
|
+
}
|
|
480
|
+
// Check if the transaction is potentially included.
|
|
481
|
+
const nonceTooLow = bundleResult.status === "bundle_submission_failure" &&
|
|
482
|
+
bundleResult.reason instanceof NonceTooLowError;
|
|
483
|
+
const allOpsFailedSimulation = bundleResult.status === "all_ops_failed_simulation" &&
|
|
484
|
+
bundleResult.rejectedUserOps.every((op) => op.reason === "AA25 invalid account nonce" ||
|
|
485
|
+
op.reason === "AA10 sender already constructed");
|
|
486
|
+
const potentiallyIncluded = nonceTooLow || allOpsFailedSimulation;
|
|
487
|
+
// log metrics
|
|
488
|
+
const replaceStatus = (() => {
|
|
489
|
+
switch (true) {
|
|
490
|
+
case potentiallyIncluded:
|
|
491
|
+
return "potentially_already_included";
|
|
492
|
+
case bundleResult?.status === "bundle_success":
|
|
493
|
+
return "replaced";
|
|
494
|
+
default:
|
|
495
|
+
return "failed";
|
|
496
|
+
}
|
|
497
|
+
})();
|
|
498
|
+
this.metrics.replacedTransactions
|
|
499
|
+
.labels({ reason, status: replaceStatus })
|
|
500
|
+
.inc();
|
|
501
|
+
if (potentiallyIncluded) {
|
|
502
|
+
this.logger.info({
|
|
503
|
+
oldTxHash,
|
|
504
|
+
userOpHashes: getUserOpHashes(bundleResult.rejectedUserOps)
|
|
505
|
+
}, "transaction potentially already included");
|
|
506
|
+
txInfo.timesPotentiallyIncluded += 1;
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (bundleResult.status === "unhandled_simulation_failure") {
|
|
510
|
+
const { rejectedUserOps, reason } = bundleResult;
|
|
511
|
+
this.failedToReplaceTransaction({
|
|
512
|
+
oldTxHash,
|
|
513
|
+
reason,
|
|
514
|
+
rejectedUserOps
|
|
515
|
+
});
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
if (bundleResult.status === "all_ops_failed_simulation") {
|
|
519
|
+
this.failedToReplaceTransaction({
|
|
520
|
+
oldTxHash,
|
|
521
|
+
reason: "all ops failed simulation",
|
|
522
|
+
rejectedUserOps: bundleResult.rejectedUserOps
|
|
523
|
+
});
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
if (bundleResult.status === "bundle_submission_failure") {
|
|
527
|
+
const { reason, rejectedUserOps } = bundleResult;
|
|
528
|
+
const submissionFailureReason = reason instanceof BaseError ? reason.name : "INTERNAL FAILURE";
|
|
529
|
+
this.failedToReplaceTransaction({
|
|
530
|
+
oldTxHash,
|
|
531
|
+
rejectedUserOps,
|
|
532
|
+
reason: submissionFailureReason
|
|
533
|
+
});
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const { rejectedUserOps, userOpsBundled, transactionRequest: newTransactionRequest, transactionHash: newTxHash } = bundleResult;
|
|
537
|
+
const userOpsReplaced = userOpsBundled;
|
|
538
|
+
const newTxInfo = {
|
|
539
|
+
...txInfo,
|
|
540
|
+
transactionRequest: newTransactionRequest,
|
|
541
|
+
transactionHash: newTxHash,
|
|
542
|
+
previousTransactionHashes: [
|
|
543
|
+
txInfo.transactionHash,
|
|
544
|
+
...txInfo.previousTransactionHashes
|
|
545
|
+
],
|
|
546
|
+
lastReplaced: Date.now(),
|
|
547
|
+
bundle: {
|
|
548
|
+
...txInfo.bundle,
|
|
549
|
+
userOps: userOpsReplaced
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
userOpsReplaced.map((userOp) => {
|
|
553
|
+
this.mempool.replaceSubmitted(userOp, newTxInfo);
|
|
574
554
|
});
|
|
555
|
+
// Drop all userOperations that were rejected during simulation.
|
|
556
|
+
this.dropUserOps(rejectedUserOps);
|
|
575
557
|
this.logger.info({
|
|
576
|
-
oldTxHash
|
|
577
|
-
newTxHash
|
|
558
|
+
oldTxHash,
|
|
559
|
+
newTxHash,
|
|
578
560
|
reason
|
|
579
561
|
}, "replaced transaction");
|
|
580
562
|
return;
|
|
581
563
|
}
|
|
564
|
+
markUserOperationsAsSubmitted(userOpInfos, transactionInfo) {
|
|
565
|
+
userOpInfos.map((userOpInfo) => {
|
|
566
|
+
const { userOpHash } = userOpInfo;
|
|
567
|
+
this.mempool.markSubmitted(userOpHash, transactionInfo);
|
|
568
|
+
this.startWatchingBlocks(this.handleBlock.bind(this));
|
|
569
|
+
this.metrics.userOperationsSubmitted
|
|
570
|
+
.labels({ status: "success" })
|
|
571
|
+
.inc();
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
resubmitUserOperations(userOps, entryPoint, reason) {
|
|
575
|
+
userOps.map((userOpInfo) => {
|
|
576
|
+
const { userOpHash, userOp } = userOpInfo;
|
|
577
|
+
this.logger.info({
|
|
578
|
+
userOpHash,
|
|
579
|
+
reason
|
|
580
|
+
}, "resubmitting user operation");
|
|
581
|
+
this.mempool.removeProcessing(userOpHash);
|
|
582
|
+
this.mempool.add(userOp, entryPoint);
|
|
583
|
+
this.metrics.userOperationsResubmitted.inc();
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
failedToReplaceTransaction({ oldTxHash, rejectedUserOps, reason }) {
|
|
587
|
+
this.logger.warn({ oldTxHash, reason }, "failed to replace transaction");
|
|
588
|
+
this.dropUserOps(rejectedUserOps);
|
|
589
|
+
}
|
|
590
|
+
removeSubmitted(userOps) {
|
|
591
|
+
userOps.map((userOpInfo) => {
|
|
592
|
+
const { userOpHash } = userOpInfo;
|
|
593
|
+
this.mempool.removeSubmitted(userOpHash);
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
markUserOpsIncluded(userOps, entryPoint, blockNumber, transactionHash, userOperationDetails) {
|
|
597
|
+
userOps.map((userOpInfo) => {
|
|
598
|
+
this.metrics.userOperationsOnChain
|
|
599
|
+
.labels({ status: "included" })
|
|
600
|
+
.inc();
|
|
601
|
+
const { userOpHash, userOp } = userOpInfo;
|
|
602
|
+
const opDetails = userOperationDetails[userOpHash];
|
|
603
|
+
const firstSubmitted = userOpInfo.addedToMempool;
|
|
604
|
+
this.metrics.userOperationInclusionDuration.observe((Date.now() - firstSubmitted) / 1000);
|
|
605
|
+
this.mempool.removeSubmitted(userOpHash);
|
|
606
|
+
this.reputationManager.updateUserOperationIncludedStatus(userOp, entryPoint, opDetails.accountDeployed);
|
|
607
|
+
if (opDetails.status === "succesful") {
|
|
608
|
+
this.eventManager.emitIncludedOnChain(userOpHash, transactionHash, blockNumber);
|
|
609
|
+
}
|
|
610
|
+
else {
|
|
611
|
+
this.eventManager.emitExecutionRevertedOnChain(userOpHash, transactionHash, opDetails.revertReason || "0x", blockNumber);
|
|
612
|
+
}
|
|
613
|
+
this.monitor.setUserOperationStatus(userOpHash, {
|
|
614
|
+
status: "included",
|
|
615
|
+
transactionHash
|
|
616
|
+
});
|
|
617
|
+
this.logger.info({
|
|
618
|
+
opHash: userOpHash,
|
|
619
|
+
transactionHash
|
|
620
|
+
}, "user op included");
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
dropUserOps(rejectedUserOps) {
|
|
624
|
+
rejectedUserOps.map((rejectedUserOp) => {
|
|
625
|
+
const { userOp, reason, userOpHash } = rejectedUserOp;
|
|
626
|
+
this.mempool.removeProcessing(userOpHash);
|
|
627
|
+
this.mempool.removeSubmitted(userOpHash);
|
|
628
|
+
this.eventManager.emitDropped(userOpHash, reason, getAAError(reason));
|
|
629
|
+
this.monitor.setUserOperationStatus(userOpHash, {
|
|
630
|
+
status: "rejected",
|
|
631
|
+
transactionHash: null
|
|
632
|
+
});
|
|
633
|
+
this.logger.warn({
|
|
634
|
+
userOperation: JSON.stringify(userOp, (_k, v) => typeof v === "bigint" ? v.toString() : v),
|
|
635
|
+
userOpHash,
|
|
636
|
+
reason
|
|
637
|
+
}, "user operation rejected");
|
|
638
|
+
this.metrics.userOperationsSubmitted
|
|
639
|
+
.labels({ status: "failed" })
|
|
640
|
+
.inc();
|
|
641
|
+
});
|
|
642
|
+
}
|
|
582
643
|
}
|
|
583
644
|
//# sourceMappingURL=executorManager.js.map
|