@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
package/lib/executor/executor.js
CHANGED
|
@@ -24,28 +24,23 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.Executor = void 0;
|
|
27
|
-
const types_1 = require("../types/index.js");
|
|
28
27
|
const utils_1 = require("../utils/index.js");
|
|
29
28
|
const sentry = __importStar(require("@sentry/node"));
|
|
30
|
-
const async_mutex_1 = require("async-mutex");
|
|
31
29
|
const viem_1 = require("viem");
|
|
32
30
|
const utils_2 = require("./utils.js");
|
|
33
31
|
const fastlane_1 = require("./fastlane.js");
|
|
32
|
+
const filterOpsAndEStimateGas_1 = require("./filterOpsAndEStimateGas.js");
|
|
34
33
|
class Executor {
|
|
35
|
-
// private unWatch: WatchBlocksReturnType | undefined
|
|
36
34
|
config;
|
|
37
|
-
senderManager;
|
|
38
35
|
logger;
|
|
39
36
|
metrics;
|
|
40
37
|
reputationManager;
|
|
41
38
|
gasPriceManager;
|
|
42
|
-
mutex;
|
|
43
39
|
mempool;
|
|
44
40
|
eventManager;
|
|
45
|
-
constructor({ config, mempool,
|
|
41
|
+
constructor({ config, mempool, reputationManager, metrics, gasPriceManager, eventManager }) {
|
|
46
42
|
this.config = config;
|
|
47
43
|
this.mempool = mempool;
|
|
48
|
-
this.senderManager = senderManager;
|
|
49
44
|
this.reputationManager = reputationManager;
|
|
50
45
|
this.logger = config.getLogger({ module: "executor" }, {
|
|
51
46
|
level: config.executorLogLevel || config.logLevel
|
|
@@ -53,243 +48,23 @@ class Executor {
|
|
|
53
48
|
this.metrics = metrics;
|
|
54
49
|
this.gasPriceManager = gasPriceManager;
|
|
55
50
|
this.eventManager = eventManager;
|
|
56
|
-
this.mutex = new async_mutex_1.Mutex();
|
|
57
51
|
}
|
|
58
52
|
cancelOps(_entryPoint, _ops) {
|
|
59
53
|
throw new Error("Method not implemented.");
|
|
60
54
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
async replaceTransaction(transactionInfo) {
|
|
68
|
-
const newRequest = { ...transactionInfo.transactionRequest };
|
|
69
|
-
let gasPriceParameters;
|
|
70
|
-
try {
|
|
71
|
-
gasPriceParameters =
|
|
72
|
-
await this.gasPriceManager.tryGetNetworkGasPrice();
|
|
73
|
-
}
|
|
74
|
-
catch (err) {
|
|
75
|
-
this.logger.error({ error: err }, "Failed to get network gas price");
|
|
76
|
-
this.markWalletProcessed(transactionInfo.executor);
|
|
77
|
-
return { status: "failed" };
|
|
78
|
-
}
|
|
79
|
-
newRequest.maxFeePerGas = (0, utils_1.scaleBigIntByPercent)(gasPriceParameters.maxFeePerGas, 115n);
|
|
80
|
-
newRequest.maxPriorityFeePerGas = (0, utils_1.scaleBigIntByPercent)(gasPriceParameters.maxPriorityFeePerGas, 115n);
|
|
81
|
-
newRequest.account = transactionInfo.executor;
|
|
82
|
-
const opsWithHashes = transactionInfo.userOperationInfos.map((opInfo) => {
|
|
83
|
-
const op = opInfo.userOperation;
|
|
84
|
-
return {
|
|
85
|
-
userOperation: opInfo.userOperation,
|
|
86
|
-
userOperationHash: (0, utils_1.getUserOperationHash)(op, transactionInfo.entryPoint, this.config.walletClient.chain.id),
|
|
87
|
-
entryPoint: opInfo.entryPoint
|
|
88
|
-
};
|
|
55
|
+
async sendHandleOpsTransaction({ txParam, gasOpts }) {
|
|
56
|
+
const { isUserOpV06, entryPoint, userOps } = txParam;
|
|
57
|
+
const handleOpsCalldata = (0, utils_2.encodeHandleOpsCalldata)({
|
|
58
|
+
userOps,
|
|
59
|
+
beneficiary: txParam.account.address
|
|
89
60
|
});
|
|
90
|
-
const [isUserOpVersion06, entryPoint] = opsWithHashes.reduce((acc, owh) => {
|
|
91
|
-
if (acc[0] !== (0, utils_1.isVersion06)(owh.userOperation) ||
|
|
92
|
-
acc[1] !== owh.entryPoint) {
|
|
93
|
-
throw new Error("All user operations must be of the same version");
|
|
94
|
-
}
|
|
95
|
-
return acc;
|
|
96
|
-
}, [
|
|
97
|
-
(0, utils_1.isVersion06)(opsWithHashes[0].userOperation),
|
|
98
|
-
opsWithHashes[0].entryPoint
|
|
99
|
-
]);
|
|
100
|
-
const ep = (0, viem_1.getContract)({
|
|
101
|
-
abi: isUserOpVersion06 ? types_1.EntryPointV06Abi : types_1.EntryPointV07Abi,
|
|
102
|
-
address: entryPoint,
|
|
103
|
-
client: {
|
|
104
|
-
public: this.config.publicClient,
|
|
105
|
-
wallet: this.config.walletClient
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
let { simulatedOps, gasLimit } = await (0, utils_2.filterOpsAndEstimateGas)(transactionInfo.entryPoint, ep, transactionInfo.executor, opsWithHashes, newRequest.nonce, newRequest.maxFeePerGas, newRequest.maxPriorityFeePerGas, this.config.blockTagSupport ? "latest" : undefined, this.config.legacyTransactions, this.config.fixedGasLimitForEstimation, this.reputationManager, this.logger);
|
|
109
|
-
const childLogger = this.logger.child({
|
|
110
|
-
transactionHash: transactionInfo.transactionHash,
|
|
111
|
-
executor: transactionInfo.executor.address
|
|
112
|
-
});
|
|
113
|
-
if (simulatedOps.length === 0) {
|
|
114
|
-
childLogger.warn("no ops to bundle");
|
|
115
|
-
this.markWalletProcessed(transactionInfo.executor);
|
|
116
|
-
return { status: "failed" };
|
|
117
|
-
}
|
|
118
|
-
if (simulatedOps.every((op) => op.reason === "AA25 invalid account nonce" ||
|
|
119
|
-
op.reason === "AA10 sender already constructed")) {
|
|
120
|
-
childLogger.trace({ reasons: simulatedOps.map((sop) => sop.reason) }, "all ops failed simulation with nonce error");
|
|
121
|
-
return { status: "potentially_already_included" };
|
|
122
|
-
}
|
|
123
|
-
if (simulatedOps.every((op) => op.reason !== undefined)) {
|
|
124
|
-
childLogger.warn("all ops failed simulation");
|
|
125
|
-
this.markWalletProcessed(transactionInfo.executor);
|
|
126
|
-
return { status: "failed" };
|
|
127
|
-
}
|
|
128
|
-
const opsToBundle = simulatedOps
|
|
129
|
-
.filter((op) => op.reason === undefined)
|
|
130
|
-
.map((op) => {
|
|
131
|
-
const opInfo = transactionInfo.userOperationInfos.find((info) => info.userOperationHash === op.owh.userOperationHash);
|
|
132
|
-
if (!opInfo) {
|
|
133
|
-
throw new Error("opInfo not found");
|
|
134
|
-
}
|
|
135
|
-
return opInfo;
|
|
136
|
-
});
|
|
137
|
-
if (this.config.localGasLimitCalculation) {
|
|
138
|
-
gasLimit = opsToBundle.reduce((acc, opInfo) => {
|
|
139
|
-
const userOperation = opInfo.userOperation;
|
|
140
|
-
return (acc +
|
|
141
|
-
userOperation.preVerificationGas +
|
|
142
|
-
3n * userOperation.verificationGasLimit +
|
|
143
|
-
userOperation.callGasLimit);
|
|
144
|
-
}, 0n);
|
|
145
|
-
}
|
|
146
|
-
// https://github.com/eth-infinitism/account-abstraction/blob/fa61290d37d079e928d92d53a122efcc63822214/contracts/core/EntryPoint.sol#L236
|
|
147
|
-
let innerHandleOpFloor = 0n;
|
|
148
|
-
for (const owh of opsToBundle) {
|
|
149
|
-
const op = owh.userOperation;
|
|
150
|
-
innerHandleOpFloor +=
|
|
151
|
-
op.callGasLimit + op.verificationGasLimit + 5000n;
|
|
152
|
-
}
|
|
153
|
-
if (gasLimit < innerHandleOpFloor) {
|
|
154
|
-
gasLimit += innerHandleOpFloor;
|
|
155
|
-
}
|
|
156
|
-
// sometimes the estimation rounds down, adding a fixed constant accounts for this
|
|
157
|
-
gasLimit += 10000n;
|
|
158
|
-
// ensures that we don't submit again with too low of a gas value
|
|
159
|
-
newRequest.gas = (0, utils_1.maxBigInt)(newRequest.gas, gasLimit);
|
|
160
|
-
// update calldata to include only ops that pass simulation
|
|
161
|
-
let txParam;
|
|
162
|
-
const userOps = opsToBundle.map((op) => isUserOpVersion06
|
|
163
|
-
? op.userOperation
|
|
164
|
-
: (0, utils_1.toPackedUserOperation)(op.userOperation));
|
|
165
|
-
txParam = {
|
|
166
|
-
isUserOpVersion06,
|
|
167
|
-
isReplacementTx: true,
|
|
168
|
-
ops: userOps,
|
|
169
|
-
entryPoint: transactionInfo.entryPoint
|
|
170
|
-
};
|
|
171
|
-
try {
|
|
172
|
-
childLogger.info({
|
|
173
|
-
newRequest: {
|
|
174
|
-
...newRequest,
|
|
175
|
-
abi: undefined,
|
|
176
|
-
chain: undefined
|
|
177
|
-
},
|
|
178
|
-
executor: newRequest.account.address,
|
|
179
|
-
opsToBundle: opsToBundle.map((opInfo) => opInfo.userOperationHash)
|
|
180
|
-
}, "replacing transaction");
|
|
181
|
-
const txHash = await this.sendHandleOpsTransaction({
|
|
182
|
-
txParam,
|
|
183
|
-
opts: this.config.legacyTransactions
|
|
184
|
-
? {
|
|
185
|
-
account: newRequest.account,
|
|
186
|
-
gasPrice: newRequest.maxFeePerGas,
|
|
187
|
-
gas: newRequest.gas,
|
|
188
|
-
nonce: newRequest.nonce
|
|
189
|
-
}
|
|
190
|
-
: {
|
|
191
|
-
account: newRequest.account,
|
|
192
|
-
maxFeePerGas: newRequest.maxFeePerGas,
|
|
193
|
-
maxPriorityFeePerGas: newRequest.maxPriorityFeePerGas,
|
|
194
|
-
gas: newRequest.gas,
|
|
195
|
-
nonce: newRequest.nonce
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
opsToBundle.map(({ entryPoint, userOperation }) => {
|
|
199
|
-
const chainId = this.config.publicClient.chain?.id;
|
|
200
|
-
const opHash = (0, utils_1.getUserOperationHash)(userOperation, entryPoint, chainId);
|
|
201
|
-
this.eventManager.emitSubmitted(opHash, txHash);
|
|
202
|
-
});
|
|
203
|
-
const newTxInfo = {
|
|
204
|
-
...transactionInfo,
|
|
205
|
-
transactionRequest: newRequest,
|
|
206
|
-
transactionHash: txHash,
|
|
207
|
-
previousTransactionHashes: [
|
|
208
|
-
transactionInfo.transactionHash,
|
|
209
|
-
...transactionInfo.previousTransactionHashes
|
|
210
|
-
],
|
|
211
|
-
lastReplaced: Date.now(),
|
|
212
|
-
userOperationInfos: opsToBundle.map((opInfo) => {
|
|
213
|
-
return {
|
|
214
|
-
entryPoint: opInfo.entryPoint,
|
|
215
|
-
userOperation: opInfo.userOperation,
|
|
216
|
-
userOperationHash: opInfo.userOperationHash,
|
|
217
|
-
lastReplaced: Date.now(),
|
|
218
|
-
firstSubmitted: opInfo.firstSubmitted
|
|
219
|
-
};
|
|
220
|
-
})
|
|
221
|
-
};
|
|
222
|
-
return {
|
|
223
|
-
status: "replaced",
|
|
224
|
-
transactionInfo: newTxInfo
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
catch (err) {
|
|
228
|
-
const e = (0, utils_1.parseViemError)(err);
|
|
229
|
-
if (!e) {
|
|
230
|
-
sentry.captureException(err);
|
|
231
|
-
childLogger.error({ error: err }, "unknown error replacing transaction");
|
|
232
|
-
}
|
|
233
|
-
if (e instanceof viem_1.NonceTooLowError) {
|
|
234
|
-
childLogger.trace({ error: e }, "nonce too low, potentially already included");
|
|
235
|
-
return { status: "potentially_already_included" };
|
|
236
|
-
}
|
|
237
|
-
if (e instanceof viem_1.FeeCapTooLowError) {
|
|
238
|
-
childLogger.warn({ error: e }, "fee cap too low, not replacing");
|
|
239
|
-
}
|
|
240
|
-
if (e instanceof viem_1.InsufficientFundsError) {
|
|
241
|
-
childLogger.warn({ error: e }, "insufficient funds, not replacing");
|
|
242
|
-
}
|
|
243
|
-
if (e instanceof viem_1.IntrinsicGasTooLowError) {
|
|
244
|
-
childLogger.warn({ error: e }, "intrinsic gas too low, not replacing");
|
|
245
|
-
}
|
|
246
|
-
childLogger.warn({ error: e }, "error replacing transaction");
|
|
247
|
-
this.markWalletProcessed(transactionInfo.executor);
|
|
248
|
-
return { status: "failed" };
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
async flushStuckTransactions() {
|
|
252
|
-
const allWallets = new Set(this.senderManager.wallets);
|
|
253
|
-
const utilityWallet = this.senderManager.utilityAccount;
|
|
254
|
-
if (utilityWallet) {
|
|
255
|
-
allWallets.add(utilityWallet);
|
|
256
|
-
}
|
|
257
|
-
const wallets = Array.from(allWallets);
|
|
258
|
-
let gasPrice;
|
|
259
|
-
try {
|
|
260
|
-
gasPrice = await this.gasPriceManager.tryGetNetworkGasPrice();
|
|
261
|
-
}
|
|
262
|
-
catch (e) {
|
|
263
|
-
this.logger.error({ error: e }, "error flushing stuck transaction");
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
const promises = wallets.map((wallet) => {
|
|
267
|
-
try {
|
|
268
|
-
(0, utils_2.flushStuckTransaction)(this.config.publicClient, this.config.walletClient, wallet, gasPrice.maxFeePerGas * 5n, this.logger);
|
|
269
|
-
}
|
|
270
|
-
catch (e) {
|
|
271
|
-
this.logger.error({ error: e }, "error flushing stuck transaction");
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
await Promise.all(promises);
|
|
275
|
-
}
|
|
276
|
-
async sendHandleOpsTransaction({ txParam, opts }) {
|
|
277
|
-
let data;
|
|
278
|
-
let to;
|
|
279
|
-
const { isUserOpVersion06, ops, entryPoint } = txParam;
|
|
280
|
-
data = (0, viem_1.encodeFunctionData)({
|
|
281
|
-
abi: isUserOpVersion06 ? types_1.EntryPointV06Abi : types_1.EntryPointV07Abi,
|
|
282
|
-
functionName: "handleOps",
|
|
283
|
-
args: [ops, opts.account.address]
|
|
284
|
-
});
|
|
285
|
-
to = entryPoint;
|
|
286
61
|
const request = await this.config.walletClient.prepareTransactionRequest({
|
|
287
|
-
to,
|
|
288
|
-
data,
|
|
289
|
-
...
|
|
62
|
+
to: entryPoint,
|
|
63
|
+
data: handleOpsCalldata,
|
|
64
|
+
...txParam,
|
|
65
|
+
...gasOpts
|
|
290
66
|
});
|
|
291
67
|
request.gas = (0, utils_1.scaleBigIntByPercent)(request.gas, this.config.executorGasMultiplier);
|
|
292
|
-
let isTransactionUnderPriced = false;
|
|
293
68
|
let attempts = 0;
|
|
294
69
|
let transactionHash;
|
|
295
70
|
const maxAttempts = 3;
|
|
@@ -297,7 +72,7 @@ class Executor {
|
|
|
297
72
|
while (attempts < maxAttempts) {
|
|
298
73
|
try {
|
|
299
74
|
if (this.config.enableFastlane &&
|
|
300
|
-
|
|
75
|
+
isUserOpV06 &&
|
|
301
76
|
!txParam.isReplacementTx &&
|
|
302
77
|
attempts === 0) {
|
|
303
78
|
const serializedTransaction = await this.config.walletClient.signTransaction(request);
|
|
@@ -314,13 +89,11 @@ class Executor {
|
|
|
314
89
|
break;
|
|
315
90
|
}
|
|
316
91
|
catch (e) {
|
|
317
|
-
isTransactionUnderPriced = false;
|
|
318
92
|
if (e instanceof viem_1.BaseError) {
|
|
319
93
|
if ((0, utils_2.isTransactionUnderpricedError)(e)) {
|
|
320
94
|
this.logger.warn("Transaction underpriced, retrying");
|
|
321
95
|
request.maxFeePerGas = (0, utils_1.scaleBigIntByPercent)(request.maxFeePerGas, 150n);
|
|
322
96
|
request.maxPriorityFeePerGas = (0, utils_1.scaleBigIntByPercent)(request.maxPriorityFeePerGas, 150n);
|
|
323
|
-
isTransactionUnderPriced = true;
|
|
324
97
|
}
|
|
325
98
|
}
|
|
326
99
|
const error = e;
|
|
@@ -346,286 +119,153 @@ class Executor {
|
|
|
346
119
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
347
120
|
}
|
|
348
121
|
}
|
|
122
|
+
attempts++;
|
|
349
123
|
if (attempts === maxAttempts) {
|
|
350
124
|
throw error;
|
|
351
125
|
}
|
|
352
|
-
attempts++;
|
|
353
126
|
}
|
|
354
127
|
}
|
|
355
|
-
if (isTransactionUnderPriced) {
|
|
356
|
-
await this.handleTransactionUnderPriced({
|
|
357
|
-
nonce: request.nonce,
|
|
358
|
-
executor: request.account
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
128
|
// needed for TS
|
|
362
129
|
if (!transactionHash) {
|
|
363
130
|
throw new Error("Transaction hash not assigned");
|
|
364
131
|
}
|
|
365
132
|
return transactionHash;
|
|
366
133
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
const
|
|
371
|
-
.filter((submitted) => {
|
|
372
|
-
const tx = submitted.transactionInfo;
|
|
373
|
-
return (tx.executor.address === executor.address &&
|
|
374
|
-
tx.transactionRequest.nonce === nonce);
|
|
375
|
-
})
|
|
376
|
-
.map(({ userOperation }) => userOperation);
|
|
377
|
-
conflictingOps.map((op) => {
|
|
378
|
-
this.logger.info(`Resubmitting ${op.userOperationHash} due to transaction underpriced`);
|
|
379
|
-
this.mempool.removeSubmitted(op.userOperationHash);
|
|
380
|
-
this.mempool.add(op.userOperation, op.entryPoint);
|
|
381
|
-
});
|
|
382
|
-
if (conflictingOps.length > 0) {
|
|
383
|
-
this.markWalletProcessed(executor);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
async bundle(entryPoint, ops) {
|
|
387
|
-
const wallet = await this.senderManager.getWallet();
|
|
388
|
-
const opsWithHashes = ops.map((userOperation) => {
|
|
389
|
-
return {
|
|
390
|
-
userOperation,
|
|
391
|
-
userOperationHash: (0, utils_1.getUserOperationHash)(userOperation, entryPoint, this.config.walletClient.chain.id)
|
|
392
|
-
};
|
|
393
|
-
});
|
|
394
|
-
const isUserOpVersion06 = opsWithHashes.reduce((acc, op) => {
|
|
395
|
-
if (acc !== (0, utils_1.isVersion06)(op.userOperation)) {
|
|
396
|
-
throw new Error("All user operations must be of the same version");
|
|
397
|
-
}
|
|
398
|
-
return acc;
|
|
399
|
-
}, (0, utils_1.isVersion06)(opsWithHashes[0].userOperation));
|
|
400
|
-
const ep = (0, viem_1.getContract)({
|
|
401
|
-
abi: isUserOpVersion06 ? types_1.EntryPointV06Abi : types_1.EntryPointV07Abi,
|
|
402
|
-
address: entryPoint,
|
|
403
|
-
client: {
|
|
404
|
-
public: this.config.publicClient,
|
|
405
|
-
wallet: this.config.walletClient
|
|
406
|
-
}
|
|
407
|
-
});
|
|
134
|
+
async bundle({ executor, userOpBundle, nonce, gasPriceParams, gasLimitSuggestion, isReplacementTx }) {
|
|
135
|
+
const { entryPoint, userOps, version } = userOpBundle;
|
|
136
|
+
const { maxFeePerGas, maxPriorityFeePerGas } = gasPriceParams;
|
|
137
|
+
const isUserOpV06 = version === "0.6";
|
|
408
138
|
let childLogger = this.logger.child({
|
|
409
|
-
|
|
139
|
+
isReplacementTx,
|
|
140
|
+
userOperations: (0, utils_2.getUserOpHashes)(userOps),
|
|
410
141
|
entryPoint
|
|
411
142
|
});
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
})
|
|
424
|
-
]);
|
|
425
|
-
}
|
|
426
|
-
catch (err) {
|
|
427
|
-
childLogger.error({ error: err }, "Failed to get parameters for bundling");
|
|
428
|
-
this.markWalletProcessed(wallet);
|
|
429
|
-
return opsWithHashes.map((owh) => {
|
|
430
|
-
return {
|
|
431
|
-
status: "resubmit",
|
|
432
|
-
info: {
|
|
433
|
-
entryPoint,
|
|
434
|
-
userOpHash: owh.userOperationHash,
|
|
435
|
-
userOperation: owh.userOperation,
|
|
436
|
-
reason: "Failed to get parameters for bundling"
|
|
437
|
-
}
|
|
438
|
-
};
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
let { gasLimit, simulatedOps } = await (0, utils_2.filterOpsAndEstimateGas)(entryPoint, ep, wallet, opsWithHashes, nonce, gasPriceParameters.maxFeePerGas, gasPriceParameters.maxPriorityFeePerGas, this.config.blockTagSupport ? "pending" : undefined, this.config.legacyTransactions, this.config.fixedGasLimitForEstimation, this.reputationManager, childLogger, (0, utils_2.getAuthorizationList)(opsWithHashes.map(({ userOperation }) => userOperation)));
|
|
442
|
-
if (simulatedOps.length === 0) {
|
|
143
|
+
let estimateResult = await (0, filterOpsAndEStimateGas_1.filterOpsAndEstimateGas)({
|
|
144
|
+
userOpBundle,
|
|
145
|
+
executor,
|
|
146
|
+
nonce,
|
|
147
|
+
maxFeePerGas,
|
|
148
|
+
maxPriorityFeePerGas,
|
|
149
|
+
reputationManager: this.reputationManager,
|
|
150
|
+
config: this.config,
|
|
151
|
+
logger: childLogger
|
|
152
|
+
});
|
|
153
|
+
if (estimateResult.status === "unhandled_failure") {
|
|
443
154
|
childLogger.error("gas limit simulation encountered unexpected failure");
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
entryPoint,
|
|
450
|
-
userOpHash: owh.userOperationHash,
|
|
451
|
-
userOperation: owh.userOperation,
|
|
452
|
-
reason: "INTERNAL FAILURE"
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
});
|
|
155
|
+
return {
|
|
156
|
+
status: "unhandled_simulation_failure",
|
|
157
|
+
rejectedUserOps: estimateResult.rejectedUserOps,
|
|
158
|
+
reason: "INTERNAL FAILURE"
|
|
159
|
+
};
|
|
456
160
|
}
|
|
457
|
-
if (
|
|
161
|
+
if (estimateResult.status === "all_ops_failed_simulation") {
|
|
458
162
|
childLogger.warn("all ops failed simulation");
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
error: {
|
|
464
|
-
entryPoint,
|
|
465
|
-
userOpHash: owh.userOperationHash,
|
|
466
|
-
userOperation: owh.userOperation,
|
|
467
|
-
reason: reason
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
});
|
|
163
|
+
return {
|
|
164
|
+
status: "all_ops_failed_simulation",
|
|
165
|
+
rejectedUserOps: estimateResult.rejectedUserOps
|
|
166
|
+
};
|
|
471
167
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
.map((op) => op.owh);
|
|
168
|
+
let { gasLimit, userOpsToBundle, rejectedUserOps } = estimateResult;
|
|
169
|
+
// Update child logger with userOperations being sent for bundling.
|
|
475
170
|
childLogger = this.logger.child({
|
|
476
|
-
|
|
171
|
+
isReplacementTx,
|
|
172
|
+
userOperations: (0, utils_2.getUserOpHashes)(userOpsToBundle),
|
|
477
173
|
entryPoint
|
|
478
174
|
});
|
|
479
|
-
//
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const op = owh.userOperation;
|
|
484
|
-
innerHandleOpFloor +=
|
|
485
|
-
op.callGasLimit + op.verificationGasLimit + 5000n;
|
|
486
|
-
totalBeneficiaryFees += (0, utils_1.getRequiredPrefund)(op);
|
|
487
|
-
}
|
|
488
|
-
if (gasLimit < innerHandleOpFloor) {
|
|
489
|
-
gasLimit += innerHandleOpFloor;
|
|
175
|
+
// Ensure that we don't submit with gas too low leading to AA95.
|
|
176
|
+
const aa95GasFloor = (0, utils_2.calculateAA95GasFloor)(userOpsToBundle);
|
|
177
|
+
if (gasLimit < aa95GasFloor) {
|
|
178
|
+
gasLimit += aa95GasFloor;
|
|
490
179
|
}
|
|
491
180
|
// sometimes the estimation rounds down, adding a fixed constant accounts for this
|
|
492
181
|
gasLimit += 10000n;
|
|
493
|
-
|
|
182
|
+
gasLimit = gasLimitSuggestion
|
|
183
|
+
? (0, utils_1.maxBigInt)(gasLimit, gasLimitSuggestion)
|
|
184
|
+
: gasLimit;
|
|
494
185
|
let transactionHash;
|
|
495
186
|
try {
|
|
496
187
|
const isLegacyTransaction = this.config.legacyTransactions;
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
gasPriceParameters.maxFeePerGas = gasPrice;
|
|
501
|
-
gasPriceParameters.maxPriorityFeePerGas = gasPrice;
|
|
502
|
-
}
|
|
503
|
-
else {
|
|
504
|
-
gasPriceParameters.maxFeePerGas = (0, utils_1.maxBigInt)(gasPrice, gasPriceParameters.maxFeePerGas || 0n);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
const authorizationList = (0, utils_2.getAuthorizationList)(opsWithHashToBundle.map(({ userOperation }) => userOperation));
|
|
508
|
-
let opts;
|
|
188
|
+
const authorizationList = (0, utils_2.getAuthorizationList)(userOpsToBundle);
|
|
189
|
+
const { maxFeePerGas, maxPriorityFeePerGas } = gasPriceParams;
|
|
190
|
+
let gasOpts;
|
|
509
191
|
if (isLegacyTransaction) {
|
|
510
|
-
|
|
192
|
+
gasOpts = {
|
|
511
193
|
type: "legacy",
|
|
512
|
-
gasPrice:
|
|
513
|
-
account: wallet,
|
|
514
|
-
gas: gasLimit,
|
|
515
|
-
nonce
|
|
194
|
+
gasPrice: maxFeePerGas
|
|
516
195
|
};
|
|
517
196
|
}
|
|
518
197
|
else if (authorizationList) {
|
|
519
|
-
|
|
198
|
+
gasOpts = {
|
|
520
199
|
type: "eip7702",
|
|
521
|
-
maxFeePerGas
|
|
522
|
-
maxPriorityFeePerGas
|
|
523
|
-
account: wallet,
|
|
524
|
-
gas: gasLimit,
|
|
525
|
-
nonce,
|
|
200
|
+
maxFeePerGas,
|
|
201
|
+
maxPriorityFeePerGas,
|
|
526
202
|
authorizationList
|
|
527
203
|
};
|
|
528
204
|
}
|
|
529
205
|
else {
|
|
530
|
-
|
|
206
|
+
gasOpts = {
|
|
531
207
|
type: "eip1559",
|
|
532
|
-
maxFeePerGas
|
|
533
|
-
maxPriorityFeePerGas
|
|
534
|
-
account: wallet,
|
|
535
|
-
gas: gasLimit,
|
|
536
|
-
nonce
|
|
208
|
+
maxFeePerGas,
|
|
209
|
+
maxPriorityFeePerGas
|
|
537
210
|
};
|
|
538
211
|
}
|
|
539
|
-
const userOps = opsWithHashToBundle.map(({ userOperation }) => {
|
|
540
|
-
if (isUserOpVersion06) {
|
|
541
|
-
return userOperation;
|
|
542
|
-
}
|
|
543
|
-
return (0, utils_1.toPackedUserOperation)(userOperation);
|
|
544
|
-
});
|
|
545
212
|
transactionHash = await this.sendHandleOpsTransaction({
|
|
546
213
|
txParam: {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
214
|
+
account: executor,
|
|
215
|
+
nonce,
|
|
216
|
+
gas: gasLimit,
|
|
217
|
+
userOps: userOpsToBundle,
|
|
218
|
+
isReplacementTx,
|
|
219
|
+
isUserOpV06,
|
|
550
220
|
entryPoint
|
|
551
221
|
},
|
|
552
|
-
|
|
222
|
+
gasOpts
|
|
553
223
|
});
|
|
554
|
-
|
|
555
|
-
|
|
224
|
+
this.eventManager.emitSubmitted({
|
|
225
|
+
userOpHashes: (0, utils_2.getUserOpHashes)(userOpsToBundle),
|
|
226
|
+
transactionHash
|
|
556
227
|
});
|
|
557
228
|
}
|
|
558
229
|
catch (err) {
|
|
559
230
|
const e = (0, utils_1.parseViemError)(err);
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
status: "resubmit",
|
|
566
|
-
info: {
|
|
567
|
-
entryPoint,
|
|
568
|
-
userOpHash: owh.userOperationHash,
|
|
569
|
-
userOperation: owh.userOperation,
|
|
570
|
-
reason: viem_1.InsufficientFundsError.name
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
sentry.captureException(err);
|
|
576
|
-
childLogger.error({ error: JSON.stringify(err) }, "error submitting bundle transaction");
|
|
577
|
-
this.markWalletProcessed(wallet);
|
|
578
|
-
return opsWithHashes.map((owh) => {
|
|
231
|
+
const { rejectedUserOps, userOpsToBundle } = estimateResult;
|
|
232
|
+
// if unknown error, return INTERNAL FAILURE
|
|
233
|
+
if (!e) {
|
|
234
|
+
sentry.captureException(err);
|
|
235
|
+
childLogger.error({ error: JSON.stringify(err) }, "error submitting bundle transaction");
|
|
579
236
|
return {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
userOperation: owh.userOperation,
|
|
585
|
-
reason: "INTERNAL FAILURE"
|
|
586
|
-
}
|
|
237
|
+
rejectedUserOps,
|
|
238
|
+
userOpsToBundle,
|
|
239
|
+
status: "bundle_submission_failure",
|
|
240
|
+
reason: "INTERNAL FAILURE"
|
|
587
241
|
};
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
const userOperationInfos = opsWithHashToBundle.map((op) => {
|
|
242
|
+
}
|
|
591
243
|
return {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
firstSubmitted: Date.now()
|
|
244
|
+
rejectedUserOps,
|
|
245
|
+
userOpsToBundle,
|
|
246
|
+
status: "bundle_submission_failure",
|
|
247
|
+
reason: e
|
|
597
248
|
};
|
|
598
|
-
}
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
249
|
+
}
|
|
250
|
+
const userOpsBundled = userOpsToBundle;
|
|
251
|
+
const bundleResult = {
|
|
252
|
+
status: "bundle_success",
|
|
253
|
+
userOpsBundled,
|
|
254
|
+
rejectedUserOps,
|
|
255
|
+
transactionHash,
|
|
604
256
|
transactionRequest: {
|
|
605
|
-
account: wallet,
|
|
606
|
-
to: ep.address,
|
|
607
257
|
gas: gasLimit,
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
},
|
|
613
|
-
executor: wallet,
|
|
614
|
-
userOperationInfos,
|
|
615
|
-
lastReplaced: Date.now(),
|
|
616
|
-
firstSubmitted: Date.now(),
|
|
617
|
-
timesPotentiallyIncluded: 0
|
|
258
|
+
maxFeePerGas: gasPriceParams.maxFeePerGas,
|
|
259
|
+
maxPriorityFeePerGas: gasPriceParams.maxPriorityFeePerGas,
|
|
260
|
+
nonce
|
|
261
|
+
}
|
|
618
262
|
};
|
|
619
|
-
const userOperationResults = (0, utils_2.simulatedOpsToResults)(simulatedOps, transactionInfo);
|
|
620
263
|
childLogger.info({
|
|
621
|
-
transactionRequest:
|
|
622
|
-
...transactionInfo.transactionRequest,
|
|
623
|
-
abi: undefined
|
|
624
|
-
},
|
|
264
|
+
transactionRequest: bundleResult.transactionRequest,
|
|
625
265
|
txHash: transactionHash,
|
|
626
|
-
opHashes:
|
|
266
|
+
opHashes: (0, utils_2.getUserOpHashes)(userOpsBundled)
|
|
627
267
|
}, "submitted bundle transaction");
|
|
628
|
-
return
|
|
268
|
+
return bundleResult;
|
|
629
269
|
}
|
|
630
270
|
}
|
|
631
271
|
exports.Executor = Executor;
|