@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.
Files changed (103) hide show
  1. package/esm/cli/config/bundler.d.ts +0 -30
  2. package/esm/cli/config/bundler.js +1 -6
  3. package/esm/cli/config/bundler.js.map +1 -1
  4. package/esm/cli/config/options.js +1 -30
  5. package/esm/cli/config/options.js.map +1 -1
  6. package/esm/cli/setupServer.js +5 -5
  7. package/esm/cli/setupServer.js.map +1 -1
  8. package/esm/executor/executor.d.ts +34 -44
  9. package/esm/executor/executor.js +103 -463
  10. package/esm/executor/executor.js.map +1 -1
  11. package/esm/executor/executorManager.d.ts +20 -10
  12. package/esm/executor/executorManager.js +371 -310
  13. package/esm/executor/executorManager.js.map +1 -1
  14. package/esm/executor/filterOpsAndEStimateGas.d.ts +28 -0
  15. package/esm/executor/filterOpsAndEStimateGas.js +191 -0
  16. package/esm/executor/filterOpsAndEStimateGas.js.map +1 -0
  17. package/esm/executor/senderManager.d.ts +2 -0
  18. package/esm/executor/senderManager.js +32 -0
  19. package/esm/executor/senderManager.js.map +1 -1
  20. package/esm/executor/utils.d.ts +21 -20
  21. package/esm/executor/utils.js +46 -185
  22. package/esm/executor/utils.js.map +1 -1
  23. package/esm/handlers/eventManager.d.ts +4 -1
  24. package/esm/handlers/eventManager.js +10 -8
  25. package/esm/handlers/eventManager.js.map +1 -1
  26. package/esm/mempool/mempool.d.ts +15 -11
  27. package/esm/mempool/mempool.js +207 -176
  28. package/esm/mempool/mempool.js.map +1 -1
  29. package/esm/mempool/store.d.ts +7 -7
  30. package/esm/mempool/store.js +13 -12
  31. package/esm/mempool/store.js.map +1 -1
  32. package/esm/rpc/nonceQueuer.js +2 -2
  33. package/esm/rpc/nonceQueuer.js.map +1 -1
  34. package/esm/rpc/rpcHandler.js +27 -31
  35. package/esm/rpc/rpcHandler.js.map +1 -1
  36. package/esm/rpc/validation/SafeValidator.d.ts +1 -1
  37. package/esm/rpc/validation/SafeValidator.js +1 -11
  38. package/esm/rpc/validation/SafeValidator.js.map +1 -1
  39. package/esm/rpc/validation/UnsafeValidator.d.ts +1 -1
  40. package/esm/rpc/validation/UnsafeValidator.js +4 -6
  41. package/esm/rpc/validation/UnsafeValidator.js.map +1 -1
  42. package/esm/types/mempool.d.ts +40 -41
  43. package/esm/types/mempool.js.map +1 -1
  44. package/esm/types/schemas.d.ts +0 -4
  45. package/esm/types/schemas.js.map +1 -1
  46. package/esm/utils/userop.d.ts +8 -3
  47. package/esm/utils/userop.js +5 -3
  48. package/esm/utils/userop.js.map +1 -1
  49. package/lib/cli/config/bundler.d.ts +0 -30
  50. package/lib/cli/config/bundler.js +1 -6
  51. package/lib/cli/config/bundler.js.map +1 -1
  52. package/lib/cli/config/options.js +1 -30
  53. package/lib/cli/config/options.js.map +1 -1
  54. package/lib/cli/setupServer.js +5 -5
  55. package/lib/cli/setupServer.js.map +1 -1
  56. package/lib/executor/executor.d.ts +34 -44
  57. package/lib/executor/executor.js +100 -460
  58. package/lib/executor/executor.js.map +1 -1
  59. package/lib/executor/executorManager.d.ts +20 -10
  60. package/lib/executor/executorManager.js +370 -309
  61. package/lib/executor/executorManager.js.map +1 -1
  62. package/lib/executor/filterOpsAndEStimateGas.d.ts +28 -0
  63. package/lib/executor/filterOpsAndEStimateGas.js +218 -0
  64. package/lib/executor/filterOpsAndEStimateGas.js.map +1 -0
  65. package/lib/executor/senderManager.d.ts +2 -0
  66. package/lib/executor/senderManager.js +32 -0
  67. package/lib/executor/senderManager.js.map +1 -1
  68. package/lib/executor/utils.d.ts +21 -20
  69. package/lib/executor/utils.js +49 -186
  70. package/lib/executor/utils.js.map +1 -1
  71. package/lib/handlers/eventManager.d.ts +4 -1
  72. package/lib/handlers/eventManager.js +10 -8
  73. package/lib/handlers/eventManager.js.map +1 -1
  74. package/lib/mempool/mempool.d.ts +15 -11
  75. package/lib/mempool/mempool.js +206 -175
  76. package/lib/mempool/mempool.js.map +1 -1
  77. package/lib/mempool/store.d.ts +7 -7
  78. package/lib/mempool/store.js +13 -12
  79. package/lib/mempool/store.js.map +1 -1
  80. package/lib/rpc/nonceQueuer.js +1 -1
  81. package/lib/rpc/nonceQueuer.js.map +1 -1
  82. package/lib/rpc/rpcHandler.js +26 -30
  83. package/lib/rpc/rpcHandler.js.map +1 -1
  84. package/lib/rpc/validation/SafeValidator.d.ts +1 -1
  85. package/lib/rpc/validation/SafeValidator.js +1 -11
  86. package/lib/rpc/validation/SafeValidator.js.map +1 -1
  87. package/lib/rpc/validation/UnsafeValidator.d.ts +1 -1
  88. package/lib/rpc/validation/UnsafeValidator.js +3 -5
  89. package/lib/rpc/validation/UnsafeValidator.js.map +1 -1
  90. package/lib/types/mempool.d.ts +40 -41
  91. package/lib/types/mempool.js.map +1 -1
  92. package/lib/types/schemas.d.ts +0 -4
  93. package/lib/types/schemas.js.map +1 -1
  94. package/lib/utils/userop.d.ts +8 -3
  95. package/lib/utils/userop.js +7 -5
  96. package/lib/utils/userop.js.map +1 -1
  97. package/package.json +1 -1
  98. package/esm/executor/types.d.ts +0 -25
  99. package/esm/executor/types.js +0 -2
  100. package/esm/executor/types.js.map +0 -1
  101. package/lib/executor/types.d.ts +0 -25
  102. package/lib/executor/types.js +0 -3
  103. package/lib/executor/types.js.map +0 -1
@@ -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(userOperation, transactionInfo) {
34
- const op = this.store
30
+ replaceSubmitted(userOpInfo, transactionInfo) {
31
+ const { userOpHash } = userOpInfo;
32
+ const existingUserOpToReplace = this.store
35
33
  .dumpSubmitted()
36
- .find((op) => op.userOperation.userOperationHash ===
37
- userOperation.userOperationHash);
38
- if (op) {
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
- userOperation,
38
+ ...userOpInfo,
42
39
  transactionInfo
43
40
  });
44
- this.monitor.setUserOperationStatus(userOperation.userOperationHash, {
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 op = this.store
48
+ const processingUserOp = this.store
52
49
  .dumpProcessing()
53
- .find((op) => op.userOperationHash === userOpHash);
54
- if (op) {
50
+ .find((userOpInfo) => userOpInfo.userOpHash === userOpHash);
51
+ if (processingUserOp) {
55
52
  this.store.removeProcessing(userOpHash);
56
53
  this.store.addSubmitted({
57
- userOperation: op,
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 mempoolOp of allOps) {
116
- const op = mempoolOp.userOperation;
117
- entities.sender.add(op.sender);
118
- const isUserOpV06 = (0, utils_1.isVersion06)(op);
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)(op.paymasterAndData)
121
- : op.paymaster;
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)(op.initCode)
127
- : op.factory;
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(userOperation, entryPoint, referencedContracts) {
137
- const opHash = (0, utils_1.getUserOperationHash)(userOperation, entryPoint, this.config.publicClient.chain.id);
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(({ userOperationHash }) => userOperationHash === opHash);
144
+ ].find((userOpInfo) => userOpInfo.userOpHash === userOpHash);
150
145
  if (existingUserOperation) {
151
146
  return [false, "Already known"];
152
147
  }
153
- if (processedOrSubmittedOps.find((opInfo) => {
154
- const mempoolUserOp = opInfo.userOperation;
155
- return (mempoolUserOp.sender === userOperation.sender &&
156
- mempoolUserOp.nonce === userOperation.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(userOperation, entryPoint);
164
- const oldUserOp = [...outstandingOps, ...processedOrSubmittedOps].find((opInfo) => {
165
- const mempoolUserOp = opInfo.userOperation;
166
- const isSameSender = mempoolUserOp.sender === userOperation.sender;
167
- if (isSameSender &&
168
- mempoolUserOp.nonce === userOperation.nonce) {
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)(userOperation) &&
174
- userOperation.initCode &&
175
- userOperation.initCode !== "0x") {
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)(userOperation) &&
183
- userOperation.factory &&
184
- userOperation.factory !== "0x") {
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((submittedOp) => submittedOp.userOperationHash === oldUserOp?.userOperationHash);
192
- if (oldUserOp) {
193
- const oldOp = oldUserOp.userOperation;
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 (oldOp.nonce === userOperation.nonce) {
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 oldMaxPriorityFeePerGas = oldOp.maxPriorityFeePerGas;
204
- const newMaxPriorityFeePerGas = userOperation.maxPriorityFeePerGas;
205
- const oldMaxFeePerGas = oldOp.maxFeePerGas;
206
- const newMaxFeePerGas = userOperation.maxFeePerGas;
207
- const incrementMaxPriorityFeePerGas = (oldMaxPriorityFeePerGas * BigInt(10)) / BigInt(100);
208
- const incrementMaxFeePerGas = (oldMaxFeePerGas * BigInt(10)) / BigInt(100);
209
- if (newMaxPriorityFeePerGas <
210
- oldMaxPriorityFeePerGas + incrementMaxPriorityFeePerGas ||
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(oldUserOp.userOperationHash);
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.userOperation;
221
- return userOp.sender === userOperation.sender;
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.getNonceKeyAndValue)(userOperation.nonce);
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.userOperation;
235
- const [opNonceKey] = (0, utils_1.getNonceKeyAndValue)(userOp.nonce);
236
- return (userOp.sender === userOperation.sender &&
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
- userOperation,
242
+ userOp,
247
243
  entryPoint,
248
- userOperationHash: opHash,
249
- firstSubmitted: oldUserOp ? oldUserOp.firstSubmitted : Date.now(),
250
- lastReplaced: Date.now(),
251
- referencedContracts
244
+ userOpHash: userOpHash,
245
+ referencedContracts,
246
+ addedToMempool: Date.now()
252
247
  });
253
- this.monitor.setUserOperationStatus(opHash, {
248
+ this.monitor.setUserOperationStatus(userOpHash, {
254
249
  status: "not_submitted",
255
250
  transactionHash: null
256
251
  });
257
- this.eventManager.emitAddedToMempool(opHash);
252
+ this.eventManager.emitAddedToMempool(userOpHash);
258
253
  return [true, ""];
259
254
  }
260
255
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>
261
- async shouldSkip(opInfo, paymasterDeposit, stakedEntityCount, knownEntities, senders, storageMap) {
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 isUserOpV06 = (0, utils_1.isVersion06)(op);
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)(op.paymasterAndData)
276
- : op.paymaster;
270
+ ? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(userOp.paymasterAndData)
271
+ : userOp.paymaster;
277
272
  const factory = isUserOpV06
278
- ? (0, utils_1.getAddressFromInitCodeOrPaymasterAndData)(op.initCode)
279
- : op.factory;
280
- const paymasterStatus = this.reputationManager.getStatus(opInfo.entryPoint, paymaster);
281
- const factoryStatus = this.reputationManager.getStatus(opInfo.entryPoint, factory);
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(opInfo.userOperationHash);
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
- opHash: opInfo.userOperationHash
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
- opHash: opInfo.userOperationHash
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(op.sender) &&
321
+ if (senders.has(userOp.sender) &&
327
322
  this.config.enforceUniqueSendersPerBundle) {
328
323
  this.logger.trace({
329
- sender: op.sender,
330
- opHash: opInfo.userOperationHash
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(op, opInfo.entryPoint);
340
+ queuedUserOperations = await this.getQueuedUserOperations(userOp, entryPoint);
346
341
  }
347
342
  validationResult = await this.validator.validateUserOperation({
348
343
  shouldCheckPrefund: false,
349
- userOperation: op,
344
+ userOperation: userOp,
350
345
  queuedUserOperations,
351
- entryPoint: opInfo.entryPoint,
352
- referencedContracts: opInfo.referencedContracts
346
+ entryPoint,
347
+ referencedContracts
353
348
  });
354
349
  }
355
350
  catch (e) {
356
351
  this.logger.error({
357
- opHash: opInfo.userOperationHash,
352
+ userOpHash,
358
353
  error: JSON.stringify(e)
359
354
  }, "2nd Validation error");
360
- this.store.removeOutstanding(opInfo.userOperationHash);
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 !== op.sender && knownEntities.sender.has(address)) {
367
+ if (address !== userOp.sender &&
368
+ knownEntities.sender.has(address)) {
373
369
  this.logger.trace({
374
370
  storageAddress,
375
- opHash: opInfo.userOperationHash
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: opInfo.entryPoint,
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
- opHash: opInfo.userOperationHash
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(op.sender);
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 process(maxGasLimit, minOps) {
432
- const outstandingUserOperations = this.store.dumpOutstanding().slice();
433
- // Sort userops before the execution
434
- // Decide the order of the userops based on the sender and nonce
435
- // If sender is the same, sort by nonce key
436
- outstandingUserOperations.sort((a, b) => {
437
- const aUserOp = a.userOperation;
438
- const bUserOp = b.userOperation;
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.getNonceKeyAndValue)(aUserOp.nonce);
441
- const [bNonceKey, bNonceValue] = (0, utils_1.getNonceKeyAndValue)(bUserOp.nonce);
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
- let opsTaken = 0;
450
- let gasUsed = 0n;
451
- const result = [];
452
- // paymaster deposit should be enough for all UserOps in the bundle.
453
- let paymasterDeposit = {};
454
- // throttled paymasters and factories are allowed only small UserOps per bundle.
455
- let stakedEntityCount = {};
456
- // each sender is allowed only once per bundle
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
- const skipResult = await this.shouldSkip(opInfo, paymasterDeposit, stakedEntityCount, knownEntities, senders, storageMap);
472
- paymasterDeposit = skipResult.paymasterDeposit;
473
- stakedEntityCount = skipResult.stakedEntityCount;
474
- knownEntities = skipResult.knownEntities;
475
- senders = skipResult.senders;
476
- storageMap = skipResult.storageMap;
477
- if (skipResult.skip) {
478
- continue;
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 null;
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(userOperation, entryPoint, _currentNonceValue) {
537
+ async getQueuedUserOperations(userOp, entryPoint, _currentNonceValue) {
507
538
  const entryPointContract = (0, viem_1.getContract)({
508
539
  address: entryPoint,
509
- abi: (0, utils_1.isVersion06)(userOperation)
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, userOperationNonceValue] = (0, utils_1.getNonceKeyAndValue)(userOperation.nonce);
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([userOperation.sender, nonceKey], {
551
+ const getNonceResult = await entryPointContract.read.getNonce([userOp.sender, nonceKey], {
523
552
  blockTag: "latest"
524
553
  });
525
- currentNonceValue = (0, utils_1.getNonceKeyAndValue)(getNonceResult)[1];
554
+ currentNonceValue = (0, utils_1.getNonceKeyAndSequence)(getNonceResult)[1];
526
555
  }
527
556
  const outstanding = this.store
528
557
  .dumpOutstanding()
529
- .map(({ userOperation }) => userOperation)
530
- .filter((mempoolUserOp) => {
531
- const [opNonceKey, opNonceValue] = (0, utils_1.getNonceKeyAndValue)(mempoolUserOp.nonce);
532
- return (mempoolUserOp.sender === userOperation.sender &&
533
- opNonceKey === nonceKey &&
534
- opNonceValue >= currentNonceValue &&
535
- opNonceValue < userOperationNonceValue);
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 [, aNonceValue] = (0, utils_1.getNonceKeyAndValue)(a.nonce);
539
- const [, bNonceValue] = (0, utils_1.getNonceKeyAndValue)(b.nonce);
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");