@pimlico/alto 0.0.0-main.20250203T212650 → 0.0.0-main.20250205T150420
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 -30
- package/esm/cli/config/bundler.js +1 -6
- package/esm/cli/config/bundler.js.map +1 -1
- package/esm/cli/config/options.js +1 -30
- 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/rpc/validation/SafeValidator.d.ts +1 -1
- package/esm/rpc/validation/SafeValidator.js +1 -11
- package/esm/rpc/validation/SafeValidator.js.map +1 -1
- package/esm/rpc/validation/UnsafeValidator.d.ts +1 -1
- package/esm/rpc/validation/UnsafeValidator.js +4 -6
- package/esm/rpc/validation/UnsafeValidator.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 -30
- package/lib/cli/config/bundler.js +1 -6
- package/lib/cli/config/bundler.js.map +1 -1
- package/lib/cli/config/options.js +1 -30
- 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/rpc/validation/SafeValidator.d.ts +1 -1
- package/lib/rpc/validation/SafeValidator.js +1 -11
- package/lib/rpc/validation/SafeValidator.js.map +1 -1
- package/lib/rpc/validation/UnsafeValidator.d.ts +1 -1
- package/lib/rpc/validation/UnsafeValidator.js +3 -5
- package/lib/rpc/validation/UnsafeValidator.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/mempool/mempool.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MemoryMempool = void 0;
|
|
4
|
-
// import { MongoClient, Collection, Filter } from "mongodb"
|
|
5
|
-
// import { PublicClient, getContract } from "viem"
|
|
6
|
-
// import { EntryPointAbi } from "../types/EntryPoint"
|
|
7
4
|
const types_1 = require("../types/index.js");
|
|
8
5
|
const utils_1 = require("../utils/index.js");
|
|
9
6
|
const viem_1 = require("viem");
|
|
@@ -30,31 +27,31 @@ class MemoryMempool {
|
|
|
30
27
|
this.throttledEntityBundleCount = 4; // we don't have any config for this as of now
|
|
31
28
|
this.eventManager = eventManager;
|
|
32
29
|
}
|
|
33
|
-
replaceSubmitted(
|
|
34
|
-
const
|
|
30
|
+
replaceSubmitted(userOpInfo, transactionInfo) {
|
|
31
|
+
const { userOpHash } = userOpInfo;
|
|
32
|
+
const existingUserOpToReplace = this.store
|
|
35
33
|
.dumpSubmitted()
|
|
36
|
-
.find((
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.store.removeSubmitted(userOperation.userOperationHash);
|
|
34
|
+
.find((userOpInfo) => userOpInfo.userOpHash === userOpHash);
|
|
35
|
+
if (existingUserOpToReplace) {
|
|
36
|
+
this.store.removeSubmitted(userOpHash);
|
|
40
37
|
this.store.addSubmitted({
|
|
41
|
-
|
|
38
|
+
...userOpInfo,
|
|
42
39
|
transactionInfo
|
|
43
40
|
});
|
|
44
|
-
this.monitor.setUserOperationStatus(
|
|
41
|
+
this.monitor.setUserOperationStatus(userOpHash, {
|
|
45
42
|
status: "submitted",
|
|
46
43
|
transactionHash: transactionInfo.transactionHash
|
|
47
44
|
});
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
markSubmitted(userOpHash, transactionInfo) {
|
|
51
|
-
const
|
|
48
|
+
const processingUserOp = this.store
|
|
52
49
|
.dumpProcessing()
|
|
53
|
-
.find((
|
|
54
|
-
if (
|
|
50
|
+
.find((userOpInfo) => userOpInfo.userOpHash === userOpHash);
|
|
51
|
+
if (processingUserOp) {
|
|
55
52
|
this.store.removeProcessing(userOpHash);
|
|
56
53
|
this.store.addSubmitted({
|
|
57
|
-
|
|
54
|
+
...processingUserOp,
|
|
58
55
|
transactionInfo
|
|
59
56
|
});
|
|
60
57
|
this.monitor.setUserOperationStatus(userOpHash, {
|
|
@@ -64,7 +61,7 @@ class MemoryMempool {
|
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
63
|
dumpOutstanding() {
|
|
67
|
-
return this.store.dumpOutstanding();
|
|
64
|
+
return this.store.dumpOutstanding().map(({ userOp }) => userOp);
|
|
68
65
|
}
|
|
69
66
|
dumpProcessing() {
|
|
70
67
|
return this.store.dumpProcessing();
|
|
@@ -112,19 +109,19 @@ class MemoryMempool {
|
|
|
112
109
|
paymasters: new Set(),
|
|
113
110
|
factories: new Set()
|
|
114
111
|
};
|
|
115
|
-
for (const
|
|
116
|
-
const
|
|
117
|
-
entities.sender.add(
|
|
118
|
-
const isUserOpV06 = (0, utils_1.isVersion06)(
|
|
112
|
+
for (const userOpInfo of allOps) {
|
|
113
|
+
const { userOp } = userOpInfo;
|
|
114
|
+
entities.sender.add(userOp.sender);
|
|
115
|
+
const isUserOpV06 = (0, utils_1.isVersion06)(userOp);
|
|
119
116
|
const paymaster = isUserOpV06
|
|
120
|
-
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(
|
|
121
|
-
:
|
|
117
|
+
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(userOp.paymasterAndData)
|
|
118
|
+
: userOp.paymaster;
|
|
122
119
|
if (paymaster) {
|
|
123
120
|
entities.paymasters.add(paymaster);
|
|
124
121
|
}
|
|
125
122
|
const factory = isUserOpV06
|
|
126
|
-
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(
|
|
127
|
-
:
|
|
123
|
+
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(userOp.initCode)
|
|
124
|
+
: userOp.factory;
|
|
128
125
|
if (factory) {
|
|
129
126
|
entities.factories.add(factory);
|
|
130
127
|
}
|
|
@@ -133,66 +130,66 @@ class MemoryMempool {
|
|
|
133
130
|
}
|
|
134
131
|
// TODO: add check for adding a userop with conflicting nonce
|
|
135
132
|
// In case of concurrent requests
|
|
136
|
-
add(
|
|
137
|
-
const
|
|
133
|
+
add(userOp, entryPoint, referencedContracts) {
|
|
134
|
+
const userOpHash = (0, utils_1.getUserOperationHash)(userOp, entryPoint, this.config.publicClient.chain.id);
|
|
138
135
|
const outstandingOps = [...this.store.dumpOutstanding()];
|
|
139
136
|
const processedOrSubmittedOps = [
|
|
140
137
|
...this.store.dumpProcessing(),
|
|
141
|
-
...this.store
|
|
142
|
-
.dumpSubmitted()
|
|
143
|
-
.map(({ userOperation }) => userOperation)
|
|
138
|
+
...this.store.dumpSubmitted()
|
|
144
139
|
];
|
|
145
140
|
// Check if the exact same userOperation is already in the mempool.
|
|
146
141
|
const existingUserOperation = [
|
|
147
142
|
...outstandingOps,
|
|
148
143
|
...processedOrSubmittedOps
|
|
149
|
-
].find((
|
|
144
|
+
].find((userOpInfo) => userOpInfo.userOpHash === userOpHash);
|
|
150
145
|
if (existingUserOperation) {
|
|
151
146
|
return [false, "Already known"];
|
|
152
147
|
}
|
|
153
|
-
if (processedOrSubmittedOps.find((
|
|
154
|
-
const mempoolUserOp =
|
|
155
|
-
return (mempoolUserOp.sender ===
|
|
156
|
-
mempoolUserOp.nonce ===
|
|
148
|
+
if (processedOrSubmittedOps.find((userOpInfo) => {
|
|
149
|
+
const { userOp: mempoolUserOp } = userOpInfo;
|
|
150
|
+
return (mempoolUserOp.sender === userOp.sender &&
|
|
151
|
+
mempoolUserOp.nonce === userOp.nonce);
|
|
157
152
|
})) {
|
|
158
153
|
return [
|
|
159
154
|
false,
|
|
160
155
|
"AA25 invalid account nonce: User operation is already in mempool and getting processed with same nonce and sender"
|
|
161
156
|
];
|
|
162
157
|
}
|
|
163
|
-
this.reputationManager.updateUserOperationSeenStatus(
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
this.reputationManager.updateUserOperationSeenStatus(userOp, entryPoint);
|
|
159
|
+
const oldUserOpInfo = [
|
|
160
|
+
...outstandingOps,
|
|
161
|
+
...processedOrSubmittedOps
|
|
162
|
+
].find((userOpInfo) => {
|
|
163
|
+
const { userOp: mempoolUserOp } = userOpInfo;
|
|
164
|
+
const isSameSender = mempoolUserOp.sender === userOp.sender;
|
|
165
|
+
if (isSameSender && mempoolUserOp.nonce === userOp.nonce) {
|
|
169
166
|
return true;
|
|
170
167
|
}
|
|
171
168
|
// Check if there is already a userOperation with initCode + same sender (stops rejected ops due to AA10).
|
|
172
169
|
if ((0, utils_1.isVersion06)(mempoolUserOp) &&
|
|
173
|
-
(0, utils_1.isVersion06)(
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
(0, utils_1.isVersion06)(userOp) &&
|
|
171
|
+
userOp.initCode &&
|
|
172
|
+
userOp.initCode !== "0x") {
|
|
176
173
|
return (isSameSender &&
|
|
177
174
|
mempoolUserOp.initCode &&
|
|
178
175
|
mempoolUserOp.initCode !== "0x");
|
|
179
176
|
}
|
|
180
177
|
// Check if there is already a userOperation with factory + same sender (stops rejected ops due to AA10).
|
|
181
178
|
if ((0, utils_1.isVersion07)(mempoolUserOp) &&
|
|
182
|
-
(0, utils_1.isVersion07)(
|
|
183
|
-
|
|
184
|
-
|
|
179
|
+
(0, utils_1.isVersion07)(userOp) &&
|
|
180
|
+
userOp.factory &&
|
|
181
|
+
userOp.factory !== "0x") {
|
|
185
182
|
return (isSameSender &&
|
|
186
183
|
mempoolUserOp.factory &&
|
|
187
184
|
mempoolUserOp.factory !== "0x");
|
|
188
185
|
}
|
|
189
186
|
return false;
|
|
190
187
|
});
|
|
191
|
-
const isOldUserOpProcessingOrSubmitted = processedOrSubmittedOps.some((
|
|
192
|
-
if (
|
|
193
|
-
const
|
|
188
|
+
const isOldUserOpProcessingOrSubmitted = processedOrSubmittedOps.some((userOpInfo) => userOpInfo.userOpHash === oldUserOpInfo?.userOpHash);
|
|
189
|
+
if (oldUserOpInfo) {
|
|
190
|
+
const { userOp: oldUserOp } = oldUserOpInfo;
|
|
194
191
|
let reason = "AA10 sender already constructed: A conflicting userOperation with initCode for this sender is already in the mempool. bump the gas price by minimum 10%";
|
|
195
|
-
if (
|
|
192
|
+
if (oldUserOp.nonce === userOp.nonce) {
|
|
196
193
|
reason =
|
|
197
194
|
"AA25 invalid account nonce: User operation already present in mempool, bump the gas price by minimum 10%";
|
|
198
195
|
}
|
|
@@ -200,25 +197,24 @@ class MemoryMempool {
|
|
|
200
197
|
if (isOldUserOpProcessingOrSubmitted) {
|
|
201
198
|
return [false, reason];
|
|
202
199
|
}
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
newMaxFeePerGas < oldMaxFeePerGas + incrementMaxFeePerGas) {
|
|
200
|
+
const oldOp = oldUserOp;
|
|
201
|
+
const newOp = userOp;
|
|
202
|
+
const hasHigherPriorityFee = newOp.maxPriorityFeePerGas >=
|
|
203
|
+
(0, utils_1.scaleBigIntByPercent)(oldOp.maxPriorityFeePerGas, 110n);
|
|
204
|
+
const hasHigherMaxFee = newOp.maxFeePerGas >=
|
|
205
|
+
(0, utils_1.scaleBigIntByPercent)(oldOp.maxFeePerGas, 110n);
|
|
206
|
+
const hasHigherFees = hasHigherPriorityFee || hasHigherMaxFee;
|
|
207
|
+
if (!hasHigherFees) {
|
|
212
208
|
return [false, reason];
|
|
213
209
|
}
|
|
214
|
-
this.store.removeOutstanding(
|
|
210
|
+
this.store.removeOutstanding(oldUserOpInfo.userOpHash);
|
|
215
211
|
}
|
|
216
212
|
// Check if mempool already includes max amount of parallel user operations
|
|
217
213
|
const parallelUserOperationsCount = this.store
|
|
218
214
|
.dumpOutstanding()
|
|
219
215
|
.filter((userOpInfo) => {
|
|
220
|
-
const userOp = userOpInfo
|
|
221
|
-
return
|
|
216
|
+
const { userOp: mempoolUserOp } = userOpInfo;
|
|
217
|
+
return mempoolUserOp.sender === userOp.sender;
|
|
222
218
|
}).length;
|
|
223
219
|
if (parallelUserOperationsCount > this.config.mempoolMaxParallelOps) {
|
|
224
220
|
return [
|
|
@@ -227,13 +223,13 @@ class MemoryMempool {
|
|
|
227
223
|
];
|
|
228
224
|
}
|
|
229
225
|
// Check if mempool already includes max amount of queued user operations
|
|
230
|
-
const [nonceKey] = (0, utils_1.
|
|
226
|
+
const [nonceKey] = (0, utils_1.getNonceKeyAndSequence)(userOp.nonce);
|
|
231
227
|
const queuedUserOperationsCount = this.store
|
|
232
228
|
.dumpOutstanding()
|
|
233
229
|
.filter((userOpInfo) => {
|
|
234
|
-
const userOp = userOpInfo
|
|
235
|
-
const [opNonceKey] = (0, utils_1.
|
|
236
|
-
return (
|
|
230
|
+
const { userOp: mempoolUserOp } = userOpInfo;
|
|
231
|
+
const [opNonceKey] = (0, utils_1.getNonceKeyAndSequence)(mempoolUserOp.nonce);
|
|
232
|
+
return (mempoolUserOp.sender === userOp.sender &&
|
|
237
233
|
opNonceKey === nonceKey);
|
|
238
234
|
}).length;
|
|
239
235
|
if (queuedUserOperationsCount > this.config.mempoolMaxQueuedOps) {
|
|
@@ -243,23 +239,21 @@ class MemoryMempool {
|
|
|
243
239
|
];
|
|
244
240
|
}
|
|
245
241
|
this.store.addOutstanding({
|
|
246
|
-
|
|
242
|
+
userOp,
|
|
247
243
|
entryPoint,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
referencedContracts
|
|
244
|
+
userOpHash: userOpHash,
|
|
245
|
+
referencedContracts,
|
|
246
|
+
addedToMempool: Date.now()
|
|
252
247
|
});
|
|
253
|
-
this.monitor.setUserOperationStatus(
|
|
248
|
+
this.monitor.setUserOperationStatus(userOpHash, {
|
|
254
249
|
status: "not_submitted",
|
|
255
250
|
transactionHash: null
|
|
256
251
|
});
|
|
257
|
-
this.eventManager.emitAddedToMempool(
|
|
252
|
+
this.eventManager.emitAddedToMempool(userOpHash);
|
|
258
253
|
return [true, ""];
|
|
259
254
|
}
|
|
260
255
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>
|
|
261
|
-
async shouldSkip(
|
|
262
|
-
const op = opInfo.userOperation;
|
|
256
|
+
async shouldSkip(userOpInfo, paymasterDeposit, stakedEntityCount, knownEntities, senders, storageMap) {
|
|
263
257
|
if (!this.config.safeMode) {
|
|
264
258
|
return {
|
|
265
259
|
skip: false,
|
|
@@ -270,18 +264,19 @@ class MemoryMempool {
|
|
|
270
264
|
storageMap
|
|
271
265
|
};
|
|
272
266
|
}
|
|
273
|
-
const
|
|
267
|
+
const { userOp, entryPoint, userOpHash, referencedContracts } = userOpInfo;
|
|
268
|
+
const isUserOpV06 = (0, utils_1.isVersion06)(userOp);
|
|
274
269
|
const paymaster = isUserOpV06
|
|
275
|
-
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(
|
|
276
|
-
:
|
|
270
|
+
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(userOp.paymasterAndData)
|
|
271
|
+
: userOp.paymaster;
|
|
277
272
|
const factory = isUserOpV06
|
|
278
|
-
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(
|
|
279
|
-
:
|
|
280
|
-
const paymasterStatus = this.reputationManager.getStatus(
|
|
281
|
-
const factoryStatus = this.reputationManager.getStatus(
|
|
273
|
+
? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(userOp.initCode)
|
|
274
|
+
: userOp.factory;
|
|
275
|
+
const paymasterStatus = this.reputationManager.getStatus(entryPoint, paymaster);
|
|
276
|
+
const factoryStatus = this.reputationManager.getStatus(entryPoint, factory);
|
|
282
277
|
if (paymasterStatus === reputationManager_1.ReputationStatuses.banned ||
|
|
283
278
|
factoryStatus === reputationManager_1.ReputationStatuses.banned) {
|
|
284
|
-
this.store.removeOutstanding(
|
|
279
|
+
this.store.removeOutstanding(userOpHash);
|
|
285
280
|
return {
|
|
286
281
|
skip: true,
|
|
287
282
|
paymasterDeposit,
|
|
@@ -296,7 +291,7 @@ class MemoryMempool {
|
|
|
296
291
|
stakedEntityCount[paymaster] >= this.throttledEntityBundleCount) {
|
|
297
292
|
this.logger.trace({
|
|
298
293
|
paymaster,
|
|
299
|
-
|
|
294
|
+
userOpHash
|
|
300
295
|
}, "Throttled paymaster skipped");
|
|
301
296
|
return {
|
|
302
297
|
skip: true,
|
|
@@ -312,7 +307,7 @@ class MemoryMempool {
|
|
|
312
307
|
stakedEntityCount[factory] >= this.throttledEntityBundleCount) {
|
|
313
308
|
this.logger.trace({
|
|
314
309
|
factory,
|
|
315
|
-
|
|
310
|
+
userOpHash
|
|
316
311
|
}, "Throttled factory skipped");
|
|
317
312
|
return {
|
|
318
313
|
skip: true,
|
|
@@ -323,11 +318,11 @@ class MemoryMempool {
|
|
|
323
318
|
storageMap
|
|
324
319
|
};
|
|
325
320
|
}
|
|
326
|
-
if (senders.has(
|
|
321
|
+
if (senders.has(userOp.sender) &&
|
|
327
322
|
this.config.enforceUniqueSendersPerBundle) {
|
|
328
323
|
this.logger.trace({
|
|
329
|
-
sender:
|
|
330
|
-
|
|
324
|
+
sender: userOp.sender,
|
|
325
|
+
userOpHash
|
|
331
326
|
}, "Sender skipped because already included in bundle");
|
|
332
327
|
return {
|
|
333
328
|
skip: true,
|
|
@@ -342,22 +337,22 @@ class MemoryMempool {
|
|
|
342
337
|
try {
|
|
343
338
|
let queuedUserOperations = [];
|
|
344
339
|
if (!isUserOpV06) {
|
|
345
|
-
queuedUserOperations = await this.getQueuedUserOperations(
|
|
340
|
+
queuedUserOperations = await this.getQueuedUserOperations(userOp, entryPoint);
|
|
346
341
|
}
|
|
347
342
|
validationResult = await this.validator.validateUserOperation({
|
|
348
343
|
shouldCheckPrefund: false,
|
|
349
|
-
userOperation:
|
|
344
|
+
userOperation: userOp,
|
|
350
345
|
queuedUserOperations,
|
|
351
|
-
entryPoint
|
|
352
|
-
referencedContracts
|
|
346
|
+
entryPoint,
|
|
347
|
+
referencedContracts
|
|
353
348
|
});
|
|
354
349
|
}
|
|
355
350
|
catch (e) {
|
|
356
351
|
this.logger.error({
|
|
357
|
-
|
|
352
|
+
userOpHash,
|
|
358
353
|
error: JSON.stringify(e)
|
|
359
354
|
}, "2nd Validation error");
|
|
360
|
-
this.store.removeOutstanding(
|
|
355
|
+
this.store.removeOutstanding(userOpHash);
|
|
361
356
|
return {
|
|
362
357
|
skip: true,
|
|
363
358
|
paymasterDeposit,
|
|
@@ -369,10 +364,11 @@ class MemoryMempool {
|
|
|
369
364
|
}
|
|
370
365
|
for (const storageAddress of Object.keys(validationResult.storageMap)) {
|
|
371
366
|
const address = (0, viem_1.getAddress)(storageAddress);
|
|
372
|
-
if (address !==
|
|
367
|
+
if (address !== userOp.sender &&
|
|
368
|
+
knownEntities.sender.has(address)) {
|
|
373
369
|
this.logger.trace({
|
|
374
370
|
storageAddress,
|
|
375
|
-
|
|
371
|
+
userOpHash
|
|
376
372
|
}, "Storage address skipped");
|
|
377
373
|
return {
|
|
378
374
|
skip: true,
|
|
@@ -388,7 +384,7 @@ class MemoryMempool {
|
|
|
388
384
|
if (paymasterDeposit[paymaster] === undefined) {
|
|
389
385
|
const entryPointContract = (0, viem_1.getContract)({
|
|
390
386
|
abi: isUserOpV06 ? types_1.EntryPointV06Abi : types_1.EntryPointV07Abi,
|
|
391
|
-
address:
|
|
387
|
+
address: entryPoint,
|
|
392
388
|
client: {
|
|
393
389
|
public: this.config.publicClient
|
|
394
390
|
}
|
|
@@ -400,7 +396,7 @@ class MemoryMempool {
|
|
|
400
396
|
validationResult.returnInfo.prefund) {
|
|
401
397
|
this.logger.trace({
|
|
402
398
|
paymaster,
|
|
403
|
-
|
|
399
|
+
userOpHash
|
|
404
400
|
}, "Paymaster skipped because of insufficient balance left to sponsor all user ops in the bundle");
|
|
405
401
|
return {
|
|
406
402
|
skip: true,
|
|
@@ -418,7 +414,7 @@ class MemoryMempool {
|
|
|
418
414
|
if (factory) {
|
|
419
415
|
stakedEntityCount[factory] = (stakedEntityCount[factory] ?? 0) + 1;
|
|
420
416
|
}
|
|
421
|
-
senders.add(
|
|
417
|
+
senders.add(userOp.sender);
|
|
422
418
|
return {
|
|
423
419
|
skip: false,
|
|
424
420
|
paymasterDeposit,
|
|
@@ -428,118 +424,153 @@ class MemoryMempool {
|
|
|
428
424
|
storageMap
|
|
429
425
|
};
|
|
430
426
|
}
|
|
431
|
-
async
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
427
|
+
async getBundles(maxBundleCount) {
|
|
428
|
+
const bundlePromises = this.config.entrypoints.map(async (entryPoint) => {
|
|
429
|
+
return await this.process({
|
|
430
|
+
entryPoint,
|
|
431
|
+
maxGasLimit: this.config.maxGasPerBundle,
|
|
432
|
+
minOpsPerBundle: 1,
|
|
433
|
+
maxBundleCount
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
const bundlesNested = await Promise.all(bundlePromises);
|
|
437
|
+
const bundles = bundlesNested.flat();
|
|
438
|
+
return bundles;
|
|
439
|
+
}
|
|
440
|
+
// Returns a bundle of userOperations in array format.
|
|
441
|
+
async process({ maxGasLimit, entryPoint, minOpsPerBundle, maxBundleCount }) {
|
|
442
|
+
let outstandingUserOps = this.store
|
|
443
|
+
.dumpOutstanding()
|
|
444
|
+
.filter((op) => op.entryPoint === entryPoint)
|
|
445
|
+
.sort((aUserOpInfo, bUserOpInfo) => {
|
|
446
|
+
// Sort userops before the execution
|
|
447
|
+
// Decide the order of the userops based on the sender and nonce
|
|
448
|
+
// If sender is the same, sort by nonce key
|
|
449
|
+
const aUserOp = aUserOpInfo.userOp;
|
|
450
|
+
const bUserOp = bUserOpInfo.userOp;
|
|
439
451
|
if (aUserOp.sender === bUserOp.sender) {
|
|
440
|
-
const [aNonceKey, aNonceValue] = (0, utils_1.
|
|
441
|
-
const [bNonceKey, bNonceValue] = (0, utils_1.
|
|
452
|
+
const [aNonceKey, aNonceValue] = (0, utils_1.getNonceKeyAndSequence)(aUserOp.nonce);
|
|
453
|
+
const [bNonceKey, bNonceValue] = (0, utils_1.getNonceKeyAndSequence)(bUserOp.nonce);
|
|
442
454
|
if (aNonceKey === bNonceKey) {
|
|
443
455
|
return Number(aNonceValue - bNonceValue);
|
|
444
456
|
}
|
|
445
457
|
return Number(aNonceKey - bNonceKey);
|
|
446
458
|
}
|
|
447
459
|
return 0;
|
|
460
|
+
})
|
|
461
|
+
.slice();
|
|
462
|
+
if (outstandingUserOps.length === 0)
|
|
463
|
+
return [];
|
|
464
|
+
// Get EntryPoint version. (Ideally version should be derived from CLI flags)
|
|
465
|
+
const isV6 = (0, utils_1.isVersion06)(outstandingUserOps[0].userOp);
|
|
466
|
+
const allSameVersion = outstandingUserOps.every((userOpInfo) => {
|
|
467
|
+
const { userOp } = userOpInfo;
|
|
468
|
+
return (0, utils_1.isVersion06)(userOp) === isV6;
|
|
448
469
|
});
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
let senders = new Set();
|
|
458
|
-
let knownEntities = this.getKnownEntities();
|
|
459
|
-
let storageMap = {};
|
|
460
|
-
for (const opInfo of outstandingUserOperations) {
|
|
461
|
-
const op = opInfo.userOperation;
|
|
462
|
-
gasUsed += op.callGasLimit + op.verificationGasLimit;
|
|
463
|
-
if ((0, utils_1.isVersion07)(op)) {
|
|
464
|
-
gasUsed +=
|
|
465
|
-
(op.paymasterPostOpGasLimit ?? 0n) +
|
|
466
|
-
(op.paymasterVerificationGasLimit ?? 0n);
|
|
467
|
-
}
|
|
468
|
-
if (gasUsed > maxGasLimit && opsTaken >= (minOps || 0)) {
|
|
470
|
+
if (!allSameVersion) {
|
|
471
|
+
throw new Error("All user operations from same EntryPoint must be of the same version");
|
|
472
|
+
}
|
|
473
|
+
const bundles = [];
|
|
474
|
+
// Process all outstanding ops.
|
|
475
|
+
while (outstandingUserOps.length > 0) {
|
|
476
|
+
// If maxBundles is set and we reached the limit, break.
|
|
477
|
+
if (maxBundleCount && bundles.length >= maxBundleCount) {
|
|
469
478
|
break;
|
|
470
479
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
480
|
+
// Setup for next bundle.
|
|
481
|
+
const currentBundle = {
|
|
482
|
+
entryPoint,
|
|
483
|
+
version: isV6 ? "0.6" : "0.7",
|
|
484
|
+
userOps: []
|
|
485
|
+
};
|
|
486
|
+
let gasUsed = 0n;
|
|
487
|
+
let paymasterDeposit = {}; // paymaster deposit should be enough for all UserOps in the bundle.
|
|
488
|
+
let stakedEntityCount = {}; // throttled paymasters and factories are allowed only small UserOps per bundle.
|
|
489
|
+
let senders = new Set(); // each sender is allowed only once per bundle
|
|
490
|
+
let knownEntities = this.getKnownEntities();
|
|
491
|
+
let storageMap = {};
|
|
492
|
+
// Keep adding ops to current bundle.
|
|
493
|
+
while (outstandingUserOps.length > 0) {
|
|
494
|
+
const userOpInfo = outstandingUserOps.shift();
|
|
495
|
+
if (!userOpInfo)
|
|
496
|
+
break;
|
|
497
|
+
const { userOp, userOpHash } = userOpInfo;
|
|
498
|
+
// NOTE: currently if a userOp is skipped due to sender enforceUniqueSendersPerBundle it will be picked up
|
|
499
|
+
// again the next time mempool.process is called.
|
|
500
|
+
const skipResult = await this.shouldSkip(userOpInfo, paymasterDeposit, stakedEntityCount, knownEntities, senders, storageMap);
|
|
501
|
+
if (skipResult.skip)
|
|
502
|
+
continue;
|
|
503
|
+
gasUsed +=
|
|
504
|
+
userOp.callGasLimit +
|
|
505
|
+
userOp.verificationGasLimit +
|
|
506
|
+
((0, utils_1.isVersion07)(userOp)
|
|
507
|
+
? (userOp.paymasterPostOpGasLimit || 0n) +
|
|
508
|
+
(userOp.paymasterVerificationGasLimit || 0n)
|
|
509
|
+
: 0n);
|
|
510
|
+
// Only break on gas limit if we've hit minOpsPerBundle.
|
|
511
|
+
if (gasUsed > maxGasLimit &&
|
|
512
|
+
currentBundle.userOps.length >= minOpsPerBundle) {
|
|
513
|
+
outstandingUserOps.unshift(userOpInfo); // re-add op to front of queue
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
// Update state based on skip result
|
|
517
|
+
paymasterDeposit = skipResult.paymasterDeposit;
|
|
518
|
+
stakedEntityCount = skipResult.stakedEntityCount;
|
|
519
|
+
knownEntities = skipResult.knownEntities;
|
|
520
|
+
senders = skipResult.senders;
|
|
521
|
+
storageMap = skipResult.storageMap;
|
|
522
|
+
this.reputationManager.decreaseUserOperationCount(userOp);
|
|
523
|
+
this.store.removeOutstanding(userOpHash);
|
|
524
|
+
this.store.addProcessing(userOpInfo);
|
|
525
|
+
// Add op to current bundle
|
|
526
|
+
currentBundle.userOps.push(userOpInfo);
|
|
527
|
+
}
|
|
528
|
+
if (currentBundle.userOps.length > 0) {
|
|
529
|
+
bundles.push(currentBundle);
|
|
479
530
|
}
|
|
480
|
-
this.reputationManager.decreaseUserOperationCount(op);
|
|
481
|
-
this.store.removeOutstanding(opInfo.userOperationHash);
|
|
482
|
-
this.store.addProcessing(opInfo);
|
|
483
|
-
result.push(opInfo);
|
|
484
|
-
opsTaken++;
|
|
485
|
-
}
|
|
486
|
-
return result;
|
|
487
|
-
}
|
|
488
|
-
get(opHash) {
|
|
489
|
-
const outstanding = this.store
|
|
490
|
-
.dumpOutstanding()
|
|
491
|
-
.find((op) => op.userOperationHash === opHash);
|
|
492
|
-
if (outstanding) {
|
|
493
|
-
return outstanding.userOperation;
|
|
494
|
-
}
|
|
495
|
-
const submitted = this.store
|
|
496
|
-
.dumpSubmitted()
|
|
497
|
-
.find((op) => op.userOperation.userOperationHash === opHash);
|
|
498
|
-
if (submitted) {
|
|
499
|
-
return submitted.userOperation.userOperation;
|
|
500
531
|
}
|
|
501
|
-
return
|
|
532
|
+
return bundles;
|
|
502
533
|
}
|
|
503
534
|
// For a specfic user operation, get all the queued user operations
|
|
504
535
|
// They should be executed first, ordered by nonce value
|
|
505
536
|
// If cuurentNonceValue is not provided, it will be fetched from the chain
|
|
506
|
-
async getQueuedUserOperations(
|
|
537
|
+
async getQueuedUserOperations(userOp, entryPoint, _currentNonceValue) {
|
|
507
538
|
const entryPointContract = (0, viem_1.getContract)({
|
|
508
539
|
address: entryPoint,
|
|
509
|
-
abi: (0, utils_1.isVersion06)(
|
|
510
|
-
? types_1.EntryPointV06Abi
|
|
511
|
-
: types_1.EntryPointV07Abi,
|
|
540
|
+
abi: (0, utils_1.isVersion06)(userOp) ? types_1.EntryPointV06Abi : types_1.EntryPointV07Abi,
|
|
512
541
|
client: {
|
|
513
542
|
public: this.config.publicClient
|
|
514
543
|
}
|
|
515
544
|
});
|
|
516
|
-
const [nonceKey,
|
|
545
|
+
const [nonceKey, nonceSequence] = (0, utils_1.getNonceKeyAndSequence)(userOp.nonce);
|
|
517
546
|
let currentNonceValue = BigInt(0);
|
|
518
547
|
if (_currentNonceValue) {
|
|
519
548
|
currentNonceValue = _currentNonceValue;
|
|
520
549
|
}
|
|
521
550
|
else {
|
|
522
|
-
const getNonceResult = await entryPointContract.read.getNonce([
|
|
551
|
+
const getNonceResult = await entryPointContract.read.getNonce([userOp.sender, nonceKey], {
|
|
523
552
|
blockTag: "latest"
|
|
524
553
|
});
|
|
525
|
-
currentNonceValue = (0, utils_1.
|
|
554
|
+
currentNonceValue = (0, utils_1.getNonceKeyAndSequence)(getNonceResult)[1];
|
|
526
555
|
}
|
|
527
556
|
const outstanding = this.store
|
|
528
557
|
.dumpOutstanding()
|
|
529
|
-
.
|
|
530
|
-
|
|
531
|
-
const [
|
|
532
|
-
return (mempoolUserOp.sender ===
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
558
|
+
.filter((userOpInfo) => {
|
|
559
|
+
const { userOp: mempoolUserOp } = userOpInfo;
|
|
560
|
+
const [mempoolNonceKey, mempoolNonceSequence] = (0, utils_1.getNonceKeyAndSequence)(mempoolUserOp.nonce);
|
|
561
|
+
return (mempoolUserOp.sender === userOp.sender &&
|
|
562
|
+
mempoolNonceKey === nonceKey &&
|
|
563
|
+
mempoolNonceSequence >= currentNonceValue &&
|
|
564
|
+
mempoolNonceSequence < nonceSequence);
|
|
536
565
|
});
|
|
537
566
|
outstanding.sort((a, b) => {
|
|
538
|
-
const
|
|
539
|
-
const
|
|
567
|
+
const aUserOp = a.userOp;
|
|
568
|
+
const bUserOp = b.userOp;
|
|
569
|
+
const [, aNonceValue] = (0, utils_1.getNonceKeyAndSequence)(aUserOp.nonce);
|
|
570
|
+
const [, bNonceValue] = (0, utils_1.getNonceKeyAndSequence)(bUserOp.nonce);
|
|
540
571
|
return Number(aNonceValue - bNonceValue);
|
|
541
572
|
});
|
|
542
|
-
return outstanding;
|
|
573
|
+
return outstanding.map((userOpInfo) => userOpInfo.userOp);
|
|
543
574
|
}
|
|
544
575
|
clear() {
|
|
545
576
|
this.store.clear("outstanding");
|