@pimlico/alto 0.0.7 → 0.0.9

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 (268) hide show
  1. package/esm/cli/alto.js +3 -1
  2. package/esm/cli/alto.js.map +1 -1
  3. package/esm/cli/config/bundler.d.ts +320 -272
  4. package/esm/cli/config/bundler.js +26 -7
  5. package/esm/cli/config/bundler.js.map +1 -1
  6. package/esm/cli/config/options.js +65 -10
  7. package/esm/cli/config/options.js.map +1 -1
  8. package/esm/cli/customTransport.js +40 -7
  9. package/esm/cli/customTransport.js.map +1 -1
  10. package/esm/cli/deploySimulationsContract.d.ts +8 -0
  11. package/esm/cli/deploySimulationsContract.js +35 -0
  12. package/esm/cli/deploySimulationsContract.js.map +1 -0
  13. package/esm/cli/handler.d.ts +2 -2
  14. package/esm/cli/handler.js +78 -89
  15. package/esm/cli/handler.js.map +1 -1
  16. package/esm/cli/instrumentation.js +4 -2
  17. package/esm/cli/instrumentation.js.map +1 -1
  18. package/esm/cli/parseArgs.d.ts +8 -0
  19. package/esm/cli/parseArgs.js +21 -0
  20. package/esm/cli/parseArgs.js.map +1 -0
  21. package/esm/cli/setupServer.d.ts +4 -9
  22. package/esm/cli/setupServer.js +100 -82
  23. package/esm/cli/setupServer.js.map +1 -1
  24. package/esm/createConfig.d.ts +15 -0
  25. package/esm/createConfig.js +8 -0
  26. package/esm/createConfig.js.map +1 -0
  27. package/esm/executor/executor.d.ts +48 -14
  28. package/esm/executor/executor.js +262 -139
  29. package/esm/executor/executor.js.map +1 -1
  30. package/esm/executor/executorManager.d.ts +14 -10
  31. package/esm/executor/executorManager.js +36 -39
  32. package/esm/executor/executorManager.js.map +1 -1
  33. package/esm/executor/senderManager.d.ts +11 -6
  34. package/esm/executor/senderManager.js +39 -36
  35. package/esm/executor/senderManager.js.map +1 -1
  36. package/esm/executor/utilityWalletMonitor.d.ts +9 -5
  37. package/esm/executor/utilityWalletMonitor.js +8 -8
  38. package/esm/executor/utilityWalletMonitor.js.map +1 -1
  39. package/esm/executor/utils.d.ts +2 -1
  40. package/esm/executor/utils.js +7 -2
  41. package/esm/executor/utils.js.map +1 -1
  42. package/esm/handlers/arbitrumGasPriceManager.d.ts +11 -0
  43. package/esm/handlers/arbitrumGasPriceManager.js +29 -0
  44. package/esm/handlers/arbitrumGasPriceManager.js.map +1 -0
  45. package/esm/handlers/eventManager.d.ts +7 -3
  46. package/esm/handlers/eventManager.js +24 -16
  47. package/esm/handlers/eventManager.js.map +1 -1
  48. package/esm/handlers/gasPriceManager.d.ts +14 -41
  49. package/esm/handlers/gasPriceManager.js +87 -208
  50. package/esm/handlers/gasPriceManager.js.map +1 -1
  51. package/esm/handlers/mantleGasPriceManager.d.ts +20 -0
  52. package/esm/handlers/mantleGasPriceManager.js +28 -0
  53. package/esm/handlers/mantleGasPriceManager.js.map +1 -0
  54. package/esm/mempool/mempool.d.ts +13 -10
  55. package/esm/mempool/mempool.js +29 -26
  56. package/esm/mempool/mempool.js.map +1 -1
  57. package/esm/mempool/reputationManager.d.ts +4 -6
  58. package/esm/mempool/reputationManager.js +25 -29
  59. package/esm/mempool/reputationManager.js.map +1 -1
  60. package/esm/mempool/store.d.ts +1 -1
  61. package/esm/rpc/estimation/gasEstimationHandler.d.ts +7 -7
  62. package/esm/rpc/estimation/gasEstimationHandler.js +18 -33
  63. package/esm/rpc/estimation/gasEstimationHandler.js.map +1 -1
  64. package/esm/rpc/estimation/gasEstimationsV06.d.ts +7 -7
  65. package/esm/rpc/estimation/gasEstimationsV06.js +90 -48
  66. package/esm/rpc/estimation/gasEstimationsV06.js.map +1 -1
  67. package/esm/rpc/estimation/gasEstimationsV07.d.ts +7 -12
  68. package/esm/rpc/estimation/gasEstimationsV07.js +53 -37
  69. package/esm/rpc/estimation/gasEstimationsV07.js.map +1 -1
  70. package/esm/rpc/nonceQueuer.d.ts +10 -6
  71. package/esm/rpc/nonceQueuer.js +10 -10
  72. package/esm/rpc/nonceQueuer.js.map +1 -1
  73. package/esm/rpc/rpcHandler.d.ts +19 -16
  74. package/esm/rpc/rpcHandler.js +98 -90
  75. package/esm/rpc/rpcHandler.js.map +1 -1
  76. package/esm/rpc/server.d.ts +9 -7
  77. package/esm/rpc/server.js +27 -25
  78. package/esm/rpc/server.js.map +1 -1
  79. package/esm/rpc/validation/SafeValidator.d.ts +11 -6
  80. package/esm/rpc/validation/SafeValidator.js +14 -11
  81. package/esm/rpc/validation/SafeValidator.js.map +1 -1
  82. package/esm/rpc/validation/TracerResultParserV06.d.ts +1 -1
  83. package/esm/rpc/validation/TracerResultParserV06.js.map +1 -1
  84. package/esm/rpc/validation/TracerResultParserV07.d.ts +1 -1
  85. package/esm/rpc/validation/TracerResultParserV07.js +1 -1
  86. package/esm/rpc/validation/TracerResultParserV07.js.map +1 -1
  87. package/esm/rpc/validation/UnsafeValidator.d.ts +11 -12
  88. package/esm/rpc/validation/UnsafeValidator.js +28 -29
  89. package/esm/rpc/validation/UnsafeValidator.js.map +1 -1
  90. package/esm/types/contracts/ArbitrumL1FeeAbi.d.ts +32 -0
  91. package/esm/types/contracts/ArbitrumL1FeeAbi.js +42 -0
  92. package/esm/types/contracts/ArbitrumL1FeeAbi.js.map +1 -0
  93. package/esm/types/contracts/EntryPointSimulationsV6.d.ts +34 -0
  94. package/esm/types/contracts/EntryPointSimulationsV6.js +48 -0
  95. package/esm/types/contracts/EntryPointSimulationsV6.js.map +1 -0
  96. package/esm/types/contracts/{EntryPointSimulations.d.ts → EntryPointSimulationsV7.d.ts} +1 -9
  97. package/esm/types/contracts/{EntryPointSimulations.js → EntryPointSimulationsV7.js} +1 -13
  98. package/esm/types/contracts/EntryPointSimulationsV7.js.map +1 -0
  99. package/esm/types/contracts/MantleBvmGasPriceOracle.d.ts +219 -0
  100. package/esm/types/contracts/MantleBvmGasPriceOracle.js +177 -0
  101. package/esm/types/contracts/MantleBvmGasPriceOracle.js.map +1 -0
  102. package/esm/types/contracts/OpL1FeeAbi.d.ts +114 -0
  103. package/esm/types/contracts/OpL1FeeAbi.js +74 -0
  104. package/esm/types/contracts/OpL1FeeAbi.js.map +1 -0
  105. package/esm/types/contracts/PimlicoEntryPointSimulations.d.ts +1 -1
  106. package/esm/types/contracts/PimlicoEntryPointSimulations.js +1 -1
  107. package/esm/types/contracts/PimlicoEntryPointSimulations.js.map +1 -1
  108. package/esm/types/contracts/index.d.ts +5 -1
  109. package/esm/types/contracts/index.js +5 -1
  110. package/esm/types/contracts/index.js.map +1 -1
  111. package/esm/types/interfaces.d.ts +2 -2
  112. package/esm/types/mempool.d.ts +1 -2
  113. package/esm/types/mempool.js.map +1 -1
  114. package/esm/types/schemas.d.ts +26 -26
  115. package/esm/types/schemas.js +3 -3
  116. package/esm/types/schemas.js.map +1 -1
  117. package/esm/types/utils.d.ts +1 -1
  118. package/esm/utils/bigInt.js +2 -2
  119. package/esm/utils/bigInt.js.map +1 -1
  120. package/esm/utils/helpers.js +1 -1
  121. package/esm/utils/helpers.js.map +1 -1
  122. package/esm/utils/metrics.d.ts +1 -0
  123. package/esm/utils/metrics.js +7 -0
  124. package/esm/utils/metrics.js.map +1 -1
  125. package/esm/utils/rpc-reply.d.ts +1 -1
  126. package/esm/utils/timedQueue.d.ts +12 -0
  127. package/esm/utils/timedQueue.js +51 -0
  128. package/esm/utils/timedQueue.js.map +1 -0
  129. package/esm/utils/userop.d.ts +3 -3
  130. package/esm/utils/userop.js +4 -3
  131. package/esm/utils/userop.js.map +1 -1
  132. package/esm/utils/validation.d.ts +14 -6
  133. package/esm/utils/validation.js +160 -168
  134. package/esm/utils/validation.js.map +1 -1
  135. package/lib/cli/alto.js +2 -0
  136. package/lib/cli/alto.js.map +1 -1
  137. package/lib/cli/config/bundler.d.ts +320 -272
  138. package/lib/cli/config/bundler.js +25 -6
  139. package/lib/cli/config/bundler.js.map +1 -1
  140. package/lib/cli/config/options.js +65 -10
  141. package/lib/cli/config/options.js.map +1 -1
  142. package/lib/cli/customTransport.js +38 -5
  143. package/lib/cli/customTransport.js.map +1 -1
  144. package/lib/cli/deploySimulationsContract.d.ts +8 -0
  145. package/lib/cli/deploySimulationsContract.js +39 -0
  146. package/lib/cli/deploySimulationsContract.js.map +1 -0
  147. package/lib/cli/handler.d.ts +2 -2
  148. package/lib/cli/handler.js +77 -88
  149. package/lib/cli/handler.js.map +1 -1
  150. package/lib/cli/instrumentation.js +4 -2
  151. package/lib/cli/instrumentation.js.map +1 -1
  152. package/lib/cli/parseArgs.d.ts +8 -0
  153. package/lib/cli/parseArgs.js +25 -0
  154. package/lib/cli/parseArgs.js.map +1 -0
  155. package/lib/cli/setupServer.d.ts +4 -9
  156. package/lib/cli/setupServer.js +100 -82
  157. package/lib/cli/setupServer.js.map +1 -1
  158. package/lib/createConfig.d.ts +15 -0
  159. package/lib/createConfig.js +12 -0
  160. package/lib/createConfig.js.map +1 -0
  161. package/lib/executor/executor.d.ts +48 -14
  162. package/lib/executor/executor.js +258 -135
  163. package/lib/executor/executor.js.map +1 -1
  164. package/lib/executor/executorManager.d.ts +14 -10
  165. package/lib/executor/executorManager.js +34 -37
  166. package/lib/executor/executorManager.js.map +1 -1
  167. package/lib/executor/senderManager.d.ts +11 -6
  168. package/lib/executor/senderManager.js +39 -36
  169. package/lib/executor/senderManager.js.map +1 -1
  170. package/lib/executor/utilityWalletMonitor.d.ts +9 -5
  171. package/lib/executor/utilityWalletMonitor.js +8 -8
  172. package/lib/executor/utilityWalletMonitor.js.map +1 -1
  173. package/lib/executor/utils.d.ts +2 -1
  174. package/lib/executor/utils.js +9 -3
  175. package/lib/executor/utils.js.map +1 -1
  176. package/lib/handlers/arbitrumGasPriceManager.d.ts +11 -0
  177. package/lib/handlers/arbitrumGasPriceManager.js +33 -0
  178. package/lib/handlers/arbitrumGasPriceManager.js.map +1 -0
  179. package/lib/handlers/eventManager.d.ts +7 -3
  180. package/lib/handlers/eventManager.js +24 -16
  181. package/lib/handlers/eventManager.js.map +1 -1
  182. package/lib/handlers/gasPriceManager.d.ts +14 -41
  183. package/lib/handlers/gasPriceManager.js +85 -206
  184. package/lib/handlers/gasPriceManager.js.map +1 -1
  185. package/lib/handlers/mantleGasPriceManager.d.ts +20 -0
  186. package/lib/handlers/mantleGasPriceManager.js +32 -0
  187. package/lib/handlers/mantleGasPriceManager.js.map +1 -0
  188. package/lib/mempool/mempool.d.ts +13 -10
  189. package/lib/mempool/mempool.js +28 -25
  190. package/lib/mempool/mempool.js.map +1 -1
  191. package/lib/mempool/reputationManager.d.ts +4 -6
  192. package/lib/mempool/reputationManager.js +25 -29
  193. package/lib/mempool/reputationManager.js.map +1 -1
  194. package/lib/mempool/store.d.ts +1 -1
  195. package/lib/rpc/estimation/gasEstimationHandler.d.ts +7 -7
  196. package/lib/rpc/estimation/gasEstimationHandler.js +18 -33
  197. package/lib/rpc/estimation/gasEstimationHandler.js.map +1 -1
  198. package/lib/rpc/estimation/gasEstimationsV06.d.ts +7 -7
  199. package/lib/rpc/estimation/gasEstimationsV06.js +88 -46
  200. package/lib/rpc/estimation/gasEstimationsV06.js.map +1 -1
  201. package/lib/rpc/estimation/gasEstimationsV07.d.ts +7 -12
  202. package/lib/rpc/estimation/gasEstimationsV07.js +52 -36
  203. package/lib/rpc/estimation/gasEstimationsV07.js.map +1 -1
  204. package/lib/rpc/nonceQueuer.d.ts +10 -6
  205. package/lib/rpc/nonceQueuer.js +9 -9
  206. package/lib/rpc/nonceQueuer.js.map +1 -1
  207. package/lib/rpc/rpcHandler.d.ts +19 -16
  208. package/lib/rpc/rpcHandler.js +97 -89
  209. package/lib/rpc/rpcHandler.js.map +1 -1
  210. package/lib/rpc/server.d.ts +9 -7
  211. package/lib/rpc/server.js +26 -24
  212. package/lib/rpc/server.js.map +1 -1
  213. package/lib/rpc/validation/SafeValidator.d.ts +11 -6
  214. package/lib/rpc/validation/SafeValidator.js +13 -10
  215. package/lib/rpc/validation/SafeValidator.js.map +1 -1
  216. package/lib/rpc/validation/TracerResultParserV06.d.ts +1 -1
  217. package/lib/rpc/validation/TracerResultParserV07.d.ts +1 -1
  218. package/lib/rpc/validation/TracerResultParserV07.js +1 -1
  219. package/lib/rpc/validation/TracerResultParserV07.js.map +1 -1
  220. package/lib/rpc/validation/UnsafeValidator.d.ts +11 -12
  221. package/lib/rpc/validation/UnsafeValidator.js +28 -29
  222. package/lib/rpc/validation/UnsafeValidator.js.map +1 -1
  223. package/lib/types/contracts/ArbitrumL1FeeAbi.d.ts +32 -0
  224. package/lib/types/contracts/ArbitrumL1FeeAbi.js +45 -0
  225. package/lib/types/contracts/ArbitrumL1FeeAbi.js.map +1 -0
  226. package/lib/types/contracts/EntryPointSimulationsV6.d.ts +34 -0
  227. package/lib/types/contracts/EntryPointSimulationsV6.js +51 -0
  228. package/lib/types/contracts/EntryPointSimulationsV6.js.map +1 -0
  229. package/lib/types/contracts/{EntryPointSimulations.d.ts → EntryPointSimulationsV7.d.ts} +1 -9
  230. package/lib/types/contracts/{EntryPointSimulations.js → EntryPointSimulationsV7.js} +2 -14
  231. package/lib/types/contracts/EntryPointSimulationsV7.js.map +1 -0
  232. package/lib/types/contracts/MantleBvmGasPriceOracle.d.ts +219 -0
  233. package/lib/types/contracts/MantleBvmGasPriceOracle.js +180 -0
  234. package/lib/types/contracts/MantleBvmGasPriceOracle.js.map +1 -0
  235. package/lib/types/contracts/OpL1FeeAbi.d.ts +114 -0
  236. package/lib/types/contracts/OpL1FeeAbi.js +77 -0
  237. package/lib/types/contracts/OpL1FeeAbi.js.map +1 -0
  238. package/lib/types/contracts/PimlicoEntryPointSimulations.d.ts +1 -1
  239. package/lib/types/contracts/PimlicoEntryPointSimulations.js +1 -1
  240. package/lib/types/contracts/PimlicoEntryPointSimulations.js.map +1 -1
  241. package/lib/types/contracts/index.d.ts +5 -1
  242. package/lib/types/contracts/index.js +5 -1
  243. package/lib/types/contracts/index.js.map +1 -1
  244. package/lib/types/interfaces.d.ts +2 -2
  245. package/lib/types/mempool.d.ts +1 -2
  246. package/lib/types/mempool.js.map +1 -1
  247. package/lib/types/schemas.d.ts +26 -26
  248. package/lib/types/schemas.js +3 -3
  249. package/lib/types/schemas.js.map +1 -1
  250. package/lib/types/utils.d.ts +1 -1
  251. package/lib/utils/bigInt.js +2 -2
  252. package/lib/utils/bigInt.js.map +1 -1
  253. package/lib/utils/metrics.d.ts +1 -0
  254. package/lib/utils/metrics.js +7 -0
  255. package/lib/utils/metrics.js.map +1 -1
  256. package/lib/utils/rpc-reply.d.ts +1 -1
  257. package/lib/utils/timedQueue.d.ts +12 -0
  258. package/lib/utils/timedQueue.js +55 -0
  259. package/lib/utils/timedQueue.js.map +1 -0
  260. package/lib/utils/userop.d.ts +3 -3
  261. package/lib/utils/userop.js +3 -2
  262. package/lib/utils/userop.js.map +1 -1
  263. package/lib/utils/validation.d.ts +14 -6
  264. package/lib/utils/validation.js +164 -168
  265. package/lib/utils/validation.js.map +1 -1
  266. package/package.json +1 -1
  267. package/esm/types/contracts/EntryPointSimulations.js.map +0 -1
  268. package/lib/types/contracts/EntryPointSimulations.js.map +0 -1
@@ -1,46 +1,33 @@
1
- import { deriveUserOperation, EntryPointV06Abi, EntryPointV07Abi } from "../types/index.js";
2
- import { getRequiredPrefund, getUserOperationHash, isVersion06, maxBigInt, parseViemError, toPackedUserOperation } from "../utils/index.js";
3
- // biome-ignore lint/style/noNamespaceImport: explicitly make it clear when sentry is used
1
+ import { EntryPointV06Abi, EntryPointV07Abi, deriveUserOperation } from "../types/index.js";
2
+ import { getRequiredPrefund, getUserOperationHash, isVersion06, maxBigInt, parseViemError, scaleBigIntByPercent, toPackedUserOperation } from "../utils/index.js";
4
3
  import * as sentry from "@sentry/node";
5
4
  import { Mutex } from "async-mutex";
6
- import { FeeCapTooLowError, InsufficientFundsError, IntrinsicGasTooLowError, NonceTooLowError, encodeFunctionData, getContract } from "viem";
7
- import { createCompressedCalldata, filterOpsAndEstimateGas, flushStuckTransaction, simulatedOpsToResults } from "./utils.js";
5
+ import { FeeCapTooLowError, InsufficientFundsError, IntrinsicGasTooLowError, NonceTooLowError, TransactionExecutionError, encodeFunctionData, getContract, BaseError, NonceTooHighError } from "viem";
6
+ import { createCompressedCalldata, filterOpsAndEstimateGas, flushStuckTransaction, simulatedOpsToResults, isTransactionUnderpricedError } from "./utils.js";
8
7
  export class Executor {
9
8
  // private unWatch: WatchBlocksReturnType | undefined
10
- publicClient;
11
- walletClient;
12
- entryPoints;
9
+ config;
13
10
  senderManager;
14
11
  logger;
15
12
  metrics;
16
- simulateTransaction;
17
- legacyTransactions;
18
- fixedGasLimitForEstimation;
19
- localGasLimitCalculation;
20
13
  reputationManager;
21
14
  compressionHandler;
22
15
  gasPriceManager;
23
- blockTagSupport;
24
16
  mutex;
17
+ mempool;
25
18
  eventManager;
26
- noProfitBundling; // if true, bundle such that all beneficiary fees go towards tx gasFees
27
- constructor(publicClient, walletClient, senderManager, reputationManager, entryPoints, logger, metrics, compressionHandler, gasPriceManager, eventManager, simulateTransaction = false, legacyTransactions = false, fixedGasLimitForEstimation, blockTagSupport = true, localGasLimitCalculation = false, noProfitBundling = false) {
28
- this.publicClient = publicClient;
29
- this.walletClient = walletClient;
19
+ constructor({ config, mempool, senderManager, reputationManager, metrics, compressionHandler, gasPriceManager, eventManager }) {
20
+ this.config = config;
21
+ this.mempool = mempool;
30
22
  this.senderManager = senderManager;
31
23
  this.reputationManager = reputationManager;
32
- this.logger = logger;
24
+ this.logger = config.getLogger({ module: "executor" }, {
25
+ level: config.executorLogLevel || config.logLevel
26
+ });
33
27
  this.metrics = metrics;
34
- this.simulateTransaction = simulateTransaction;
35
- this.legacyTransactions = legacyTransactions;
36
- this.fixedGasLimitForEstimation = fixedGasLimitForEstimation;
37
- this.localGasLimitCalculation = localGasLimitCalculation;
38
28
  this.compressionHandler = compressionHandler;
39
29
  this.gasPriceManager = gasPriceManager;
40
30
  this.eventManager = eventManager;
41
- this.blockTagSupport = blockTagSupport;
42
- this.entryPoints = entryPoints;
43
- this.noProfitBundling = noProfitBundling;
44
31
  this.mutex = new Mutex();
45
32
  }
46
33
  getCompressionHandler() {
@@ -60,7 +47,16 @@ export class Executor {
60
47
  }
61
48
  async replaceTransaction(transactionInfo) {
62
49
  const newRequest = { ...transactionInfo.transactionRequest };
63
- const gasPriceParameters = await this.gasPriceManager.getGasPrice();
50
+ let gasPriceParameters;
51
+ try {
52
+ gasPriceParameters =
53
+ await this.gasPriceManager.tryGetNetworkGasPrice();
54
+ }
55
+ catch (err) {
56
+ this.logger.error({ error: err }, "Failed to get network gas price");
57
+ this.markWalletProcessed(transactionInfo.executor);
58
+ return { status: "failed" };
59
+ }
64
60
  newRequest.maxFeePerGas = maxBigInt(gasPriceParameters.maxFeePerGas, (newRequest.maxFeePerGas * 11n + 9n) / 10n);
65
61
  newRequest.maxPriorityFeePerGas = maxBigInt(gasPriceParameters.maxPriorityFeePerGas, (newRequest.maxPriorityFeePerGas * 11n + 9n) / 10n);
66
62
  newRequest.account = transactionInfo.executor;
@@ -68,7 +64,7 @@ export class Executor {
68
64
  const op = deriveUserOperation(opInfo.mempoolUserOperation);
69
65
  return {
70
66
  mempoolUserOperation: opInfo.mempoolUserOperation,
71
- userOperationHash: getUserOperationHash(op, transactionInfo.entryPoint, this.walletClient.chain.id),
67
+ userOperationHash: getUserOperationHash(op, transactionInfo.entryPoint, this.config.walletClient.chain.id),
72
68
  entryPoint: opInfo.entryPoint
73
69
  };
74
70
  });
@@ -89,8 +85,8 @@ export class Executor {
89
85
  abi: isUserOpVersion06 ? EntryPointV06Abi : EntryPointV07Abi,
90
86
  address: entryPoint,
91
87
  client: {
92
- public: this.publicClient,
93
- wallet: this.walletClient
88
+ public: this.config.publicClient,
89
+ wallet: this.config.walletClient
94
90
  }
95
91
  });
96
92
  callContext = {
@@ -101,13 +97,13 @@ export class Executor {
101
97
  else {
102
98
  const compressionHandler = this.getCompressionHandler();
103
99
  callContext = {
104
- publicClient: this.publicClient,
100
+ publicClient: this.config.publicClient,
105
101
  bundleBulker: compressionHandler.bundleBulkerAddress,
106
102
  perOpInflatorId: compressionHandler.perOpInflatorId,
107
103
  type: "compressed"
108
104
  };
109
105
  }
110
- let { simulatedOps, gasLimit } = await filterOpsAndEstimateGas(transactionInfo.entryPoint, callContext, transactionInfo.executor, opsWithHashes, newRequest.nonce, newRequest.maxFeePerGas, newRequest.maxPriorityFeePerGas, this.blockTagSupport ? "latest" : undefined, this.legacyTransactions, this.fixedGasLimitForEstimation, this.reputationManager, this.logger);
106
+ let { simulatedOps, gasLimit } = await filterOpsAndEstimateGas(transactionInfo.entryPoint, callContext, transactionInfo.executor, opsWithHashes, newRequest.nonce, newRequest.maxFeePerGas, newRequest.maxPriorityFeePerGas, this.config.blockTagSupport ? "latest" : undefined, this.config.legacyTransactions, this.config.fixedGasLimitForEstimation, this.reputationManager, this.logger);
111
107
  const childLogger = this.logger.child({
112
108
  transactionHash: transactionInfo.transactionHash,
113
109
  executor: transactionInfo.executor.address
@@ -136,7 +132,7 @@ export class Executor {
136
132
  }
137
133
  return opInfo;
138
134
  });
139
- if (this.localGasLimitCalculation) {
135
+ if (this.config.localGasLimitCalculation) {
140
136
  gasLimit = opsToBundle.reduce((acc, opInfo) => {
141
137
  const userOperation = deriveUserOperation(opInfo.mempoolUserOperation);
142
138
  return (acc +
@@ -160,6 +156,7 @@ export class Executor {
160
156
  // ensures that we don't submit again with too low of a gas value
161
157
  newRequest.gas = maxBigInt(newRequest.gas, gasLimit);
162
158
  // update calldata to include only ops that pass simulation
159
+ let txParam;
163
160
  if (transactionInfo.transactionType === "default") {
164
161
  const isUserOpVersion06 = opsWithHashes.reduce((acc, op) => {
165
162
  if (acc !==
@@ -168,27 +165,22 @@ export class Executor {
168
165
  }
169
166
  return acc;
170
167
  }, isVersion06(opsWithHashes[0].mempoolUserOperation));
171
- newRequest.data = isUserOpVersion06
172
- ? encodeFunctionData({
173
- abi: EntryPointV06Abi,
174
- functionName: "handleOps",
175
- args: [
176
- opsToBundle.map((opInfo) => opInfo.mempoolUserOperation),
177
- transactionInfo.executor.address
178
- ]
179
- })
180
- : encodeFunctionData({
181
- abi: EntryPointV07Abi,
182
- functionName: "handleOps",
183
- args: [
184
- opsToBundle.map((opInfo) => toPackedUserOperation(opInfo.mempoolUserOperation)),
185
- transactionInfo.executor.address
186
- ]
187
- });
168
+ const userOps = opsToBundle.map((op) => isUserOpVersion06
169
+ ? op.mempoolUserOperation
170
+ : toPackedUserOperation(op.mempoolUserOperation));
171
+ txParam = {
172
+ type: "default",
173
+ isUserOpVersion06,
174
+ ops: userOps,
175
+ entryPoint: transactionInfo.entryPoint
176
+ };
188
177
  }
189
- else if (transactionInfo.transactionType === "compressed") {
190
- const compressedOps = opsToBundle.map((opInfo) => opInfo.mempoolUserOperation);
191
- newRequest.data = createCompressedCalldata(compressedOps, this.getCompressionHandler().perOpInflatorId);
178
+ else {
179
+ const compressedOps = opsToBundle.map(({ mempoolUserOperation }) => mempoolUserOperation);
180
+ txParam = {
181
+ type: "compressed",
182
+ compressedOps: compressedOps
183
+ };
192
184
  }
193
185
  try {
194
186
  childLogger.info({
@@ -200,20 +192,27 @@ export class Executor {
200
192
  executor: newRequest.account.address,
201
193
  opsToBundle: opsToBundle.map((opInfo) => opInfo.userOperationHash)
202
194
  }, "replacing transaction");
203
- const txHash = await this.walletClient.sendTransaction(this.legacyTransactions
204
- ? {
205
- ...newRequest,
206
- gasPrice: newRequest.maxFeePerGas,
207
- maxFeePerGas: undefined,
208
- maxPriorityFeePerGas: undefined,
209
- type: "legacy",
210
- accessList: undefined
211
- }
212
- : newRequest);
213
- opsToBundle.map((opToBundle) => {
214
- const op = deriveUserOperation(opToBundle.mempoolUserOperation);
215
- const chainId = this.publicClient.chain?.id;
216
- const opHash = getUserOperationHash(op, opToBundle.entryPoint, chainId);
195
+ const txHash = await this.sendHandleOpsTransaction({
196
+ txParam,
197
+ opts: this.config.legacyTransactions
198
+ ? {
199
+ account: newRequest.account,
200
+ gasPrice: newRequest.maxFeePerGas,
201
+ gas: newRequest.gas,
202
+ nonce: newRequest.nonce
203
+ }
204
+ : {
205
+ account: newRequest.account,
206
+ maxFeePerGas: newRequest.maxFeePerGas,
207
+ maxPriorityFeePerGas: newRequest.maxPriorityFeePerGas,
208
+ gas: newRequest.gas,
209
+ nonce: newRequest.nonce
210
+ }
211
+ });
212
+ opsToBundle.map(({ entryPoint, mempoolUserOperation }) => {
213
+ const op = deriveUserOperation(mempoolUserOperation);
214
+ const chainId = this.config.publicClient.chain?.id;
215
+ const opHash = getUserOperationHash(op, entryPoint, chainId);
217
216
  this.eventManager.emitSubmitted(opHash, txHash);
218
217
  });
219
218
  const newTxInfo = {
@@ -271,18 +270,129 @@ export class Executor {
271
270
  allWallets.add(utilityWallet);
272
271
  }
273
272
  const wallets = Array.from(allWallets);
274
- const gasPrice = await this.gasPriceManager.getGasPrice();
273
+ const gasPrice = await this.gasPriceManager.tryGetNetworkGasPrice();
275
274
  const promises = wallets.map((wallet) => {
276
- flushStuckTransaction(this.publicClient, this.walletClient, wallet, gasPrice.maxFeePerGas * 5n, this.logger);
275
+ try {
276
+ flushStuckTransaction(this.config.publicClient, this.config.walletClient, wallet, gasPrice.maxFeePerGas * 5n, this.logger);
277
+ }
278
+ catch (e) {
279
+ this.logger.error({ error: e }, "error flushing stuck transaction");
280
+ }
277
281
  });
278
282
  await Promise.all(promises);
279
283
  }
284
+ async sendHandleOpsTransaction({ txParam, opts }) {
285
+ let data;
286
+ let to;
287
+ if (txParam.type === "default") {
288
+ const { isUserOpVersion06, ops, entryPoint } = txParam;
289
+ data = encodeFunctionData({
290
+ abi: isUserOpVersion06 ? EntryPointV06Abi : EntryPointV07Abi,
291
+ functionName: "handleOps",
292
+ args: [ops, opts.account.address]
293
+ });
294
+ to = entryPoint;
295
+ }
296
+ else {
297
+ const { compressedOps } = txParam;
298
+ const compressionHandler = this.getCompressionHandler();
299
+ data = createCompressedCalldata(compressedOps, compressionHandler.perOpInflatorId);
300
+ to = compressionHandler.bundleBulkerAddress;
301
+ }
302
+ const request = await this.config.walletClient.prepareTransactionRequest({
303
+ to,
304
+ data,
305
+ ...opts
306
+ });
307
+ let isTransactionUnderPriced = false;
308
+ let attempts = 0;
309
+ let transactionHash;
310
+ const maxAttempts = 3;
311
+ // Try sending the transaction and updating relevant fields if there is an error.
312
+ while (attempts < maxAttempts) {
313
+ try {
314
+ transactionHash =
315
+ await this.config.walletClient.sendTransaction(request);
316
+ break;
317
+ }
318
+ catch (e) {
319
+ isTransactionUnderPriced = false;
320
+ let isErrorHandled = false;
321
+ if (e instanceof BaseError) {
322
+ if (isTransactionUnderpricedError(e)) {
323
+ this.logger.warn("Transaction underpriced, retrying");
324
+ request.maxFeePerGas = scaleBigIntByPercent(request.maxFeePerGas, 150);
325
+ request.maxPriorityFeePerGas = scaleBigIntByPercent(request.maxPriorityFeePerGas, 150);
326
+ isErrorHandled = true;
327
+ isTransactionUnderPriced = true;
328
+ }
329
+ }
330
+ const error = e;
331
+ if (error instanceof TransactionExecutionError) {
332
+ const cause = error.cause;
333
+ if (cause instanceof NonceTooLowError ||
334
+ cause instanceof NonceTooHighError) {
335
+ this.logger.warn("Nonce too low, retrying");
336
+ request.nonce =
337
+ await this.config.publicClient.getTransactionCount({
338
+ address: request.from,
339
+ blockTag: "pending"
340
+ });
341
+ isErrorHandled = true;
342
+ }
343
+ if (cause instanceof IntrinsicGasTooLowError) {
344
+ this.logger.warn("Intrinsic gas too low, retrying");
345
+ request.gas = scaleBigIntByPercent(request.gas, 150);
346
+ isErrorHandled = true;
347
+ }
348
+ // This is thrown by OP-Stack chains that use proxyd.
349
+ // ref: https://github.com/ethereum-optimism/optimism/issues/2618#issuecomment-1630272888
350
+ if (cause.details?.includes("no backends available")) {
351
+ this.logger.warn("no backends avaiable error, retrying after 500ms");
352
+ await new Promise((resolve) => setTimeout(resolve, 500));
353
+ isErrorHandled = true;
354
+ }
355
+ }
356
+ if (attempts === maxAttempts || !isErrorHandled) {
357
+ throw error;
358
+ }
359
+ attempts++;
360
+ }
361
+ }
362
+ if (isTransactionUnderPriced) {
363
+ await this.handleTransactionUnderPriced({
364
+ nonce: request.nonce,
365
+ executor: request.from
366
+ });
367
+ }
368
+ // needed for TS
369
+ if (!transactionHash) {
370
+ throw new Error("Transaction hash not assigned");
371
+ }
372
+ return transactionHash;
373
+ }
374
+ // Occurs when tx was sent with conflicting nonce, we want to resubmit all conflicting ops
375
+ async handleTransactionUnderPriced({ nonce, executor }) {
376
+ const submitted = this.mempool.dumpSubmittedOps();
377
+ const conflictingOps = submitted
378
+ .filter((submitted) => {
379
+ const tx = submitted.transactionInfo;
380
+ return (tx.executor.address === executor &&
381
+ tx.transactionRequest.nonce === nonce);
382
+ })
383
+ .map(({ userOperation }) => userOperation);
384
+ conflictingOps.map((op) => {
385
+ this.logger.info(`Resubmitting ${op.userOperationHash} due to transaction underpriced`);
386
+ this.mempool.removeSubmitted(op.userOperationHash);
387
+ this.mempool.add(op.mempoolUserOperation, op.entryPoint);
388
+ });
389
+ }
280
390
  async bundle(entryPoint, ops) {
281
391
  const wallet = await this.senderManager.getWallet();
282
392
  const opsWithHashes = ops.map((op) => {
283
393
  return {
284
394
  mempoolUserOperation: op,
285
- userOperationHash: getUserOperationHash(op, entryPoint, this.walletClient.chain.id)
395
+ userOperationHash: getUserOperationHash(op, entryPoint, this.config.walletClient.chain.id)
286
396
  };
287
397
  });
288
398
  const isUserOpVersion06 = opsWithHashes.reduce((acc, op) => {
@@ -296,8 +406,8 @@ export class Executor {
296
406
  abi: isUserOpVersion06 ? EntryPointV06Abi : EntryPointV07Abi,
297
407
  address: entryPoint,
298
408
  client: {
299
- public: this.publicClient,
300
- wallet: this.walletClient
409
+ public: this.config.publicClient,
410
+ wallet: this.config.walletClient
301
411
  }
302
412
  });
303
413
  let childLogger = this.logger.child({
@@ -305,18 +415,39 @@ export class Executor {
305
415
  entryPoint
306
416
  });
307
417
  childLogger.debug("bundling user operation");
308
- const gasPriceParameters = await this.gasPriceManager.getGasPrice();
309
- childLogger.debug({ gasPriceParameters }, "got gas price");
310
- const nonce = await this.publicClient.getTransactionCount({
311
- address: wallet.address,
312
- blockTag: "pending"
313
- });
314
- childLogger.trace({ nonce }, "got nonce");
418
+ // These calls can throw, so we try/catch them to mark wallet as processed in event of error.
419
+ let nonce;
420
+ let gasPriceParameters;
421
+ try {
422
+ ;
423
+ [gasPriceParameters, nonce] = await Promise.all([
424
+ this.gasPriceManager.tryGetNetworkGasPrice(),
425
+ this.config.publicClient.getTransactionCount({
426
+ address: wallet.address,
427
+ blockTag: "pending"
428
+ })
429
+ ]);
430
+ }
431
+ catch (err) {
432
+ childLogger.error({ error: err }, "Failed to get parameters for bundling");
433
+ this.markWalletProcessed(wallet);
434
+ return opsWithHashes.map((owh) => {
435
+ return {
436
+ status: "resubmit",
437
+ info: {
438
+ entryPoint,
439
+ userOpHash: owh.userOperationHash,
440
+ userOperation: owh.mempoolUserOperation,
441
+ reason: "Failed to get parameters for bundling"
442
+ }
443
+ };
444
+ });
445
+ }
315
446
  const callContext = {
316
447
  ep,
317
448
  type: "default"
318
449
  };
319
- let { gasLimit, simulatedOps } = await filterOpsAndEstimateGas(entryPoint, callContext, wallet, opsWithHashes, nonce, gasPriceParameters.maxFeePerGas, gasPriceParameters.maxPriorityFeePerGas, this.blockTagSupport ? "pending" : undefined, this.legacyTransactions, this.fixedGasLimitForEstimation, this.reputationManager, childLogger);
450
+ let { gasLimit, simulatedOps } = await filterOpsAndEstimateGas(entryPoint, callContext, wallet, opsWithHashes, nonce, gasPriceParameters.maxFeePerGas, gasPriceParameters.maxPriorityFeePerGas, this.config.blockTagSupport ? "pending" : undefined, this.config.legacyTransactions, this.config.fixedGasLimitForEstimation, this.reputationManager, childLogger);
320
451
  if (simulatedOps.length === 0) {
321
452
  childLogger.error("gas limit simulation encountered unexpected failure");
322
453
  this.markWalletProcessed(wallet);
@@ -371,14 +502,14 @@ export class Executor {
371
502
  childLogger.debug({ gasLimit }, "got gas limit");
372
503
  let transactionHash;
373
504
  try {
374
- const isLegacyTransaction = this.legacyTransactions;
505
+ const isLegacyTransaction = this.config.legacyTransactions;
375
506
  const gasOptions = isLegacyTransaction
376
507
  ? { gasPrice: gasPriceParameters.maxFeePerGas }
377
508
  : {
378
509
  maxFeePerGas: gasPriceParameters.maxFeePerGas,
379
510
  maxPriorityFeePerGas: gasPriceParameters.maxPriorityFeePerGas
380
511
  };
381
- if (this.noProfitBundling) {
512
+ if (this.config.noProfitBundling) {
382
513
  const gasPrice = totalBeneficiaryFees / gasLimit;
383
514
  if (isLegacyTransaction) {
384
515
  gasOptions.gasPrice = gasPrice;
@@ -396,7 +527,15 @@ export class Executor {
396
527
  const userOps = opsWithHashToBundle.map((owh) => isUserOpVersion06
397
528
  ? owh.mempoolUserOperation
398
529
  : toPackedUserOperation(owh.mempoolUserOperation));
399
- transactionHash = await ep.write.handleOps([userOps, wallet.address], opts);
530
+ transactionHash = await this.sendHandleOpsTransaction({
531
+ txParam: {
532
+ type: "default",
533
+ ops: userOps,
534
+ isUserOpVersion06,
535
+ entryPoint
536
+ },
537
+ opts
538
+ });
400
539
  opsWithHashToBundle.map(({ userOperationHash }) => {
401
540
  this.eventManager.emitSubmitted(userOperationHash, transactionHash);
402
541
  });
@@ -418,23 +557,6 @@ export class Executor {
418
557
  };
419
558
  });
420
559
  }
421
- if (e?.details
422
- .toLowerCase()
423
- .includes("replacement transaction underpriced")) {
424
- childLogger.error({ error: e }, "replacement transaction underpriced");
425
- this.markWalletProcessed(wallet);
426
- return opsWithHashToBundle.map((owh) => {
427
- return {
428
- status: "resubmit",
429
- info: {
430
- entryPoint,
431
- userOpHash: owh.userOperationHash,
432
- userOperation: owh.mempoolUserOperation,
433
- reason: "replacement transaction underpriced"
434
- }
435
- };
436
- });
437
- }
438
560
  sentry.captureException(err);
439
561
  childLogger.error({ error: JSON.stringify(err) }, "error submitting bundle transaction");
440
562
  this.markWalletProcessed(wallet);
@@ -468,25 +590,8 @@ export class Executor {
468
590
  transactionRequest: {
469
591
  account: wallet,
470
592
  to: ep.address,
471
- data: isUserOpVersion06
472
- ? encodeFunctionData({
473
- abi: ep.abi,
474
- functionName: "handleOps",
475
- args: [
476
- opsWithHashToBundle.map((owh) => owh.mempoolUserOperation),
477
- wallet.address
478
- ]
479
- })
480
- : encodeFunctionData({
481
- abi: ep.abi,
482
- functionName: "handleOps",
483
- args: [
484
- opsWithHashToBundle.map((owh) => toPackedUserOperation(owh.mempoolUserOperation)),
485
- wallet.address
486
- ]
487
- }),
488
593
  gas: gasLimit,
489
- chain: this.walletClient.chain,
594
+ chain: this.config.walletClient.chain,
490
595
  maxFeePerGas: gasPriceParameters.maxFeePerGas,
491
596
  maxPriorityFeePerGas: gasPriceParameters.maxPriorityFeePerGas,
492
597
  nonce: nonce
@@ -516,15 +621,36 @@ export class Executor {
516
621
  entryPoint: entryPoint
517
622
  });
518
623
  childLogger.debug("bundling compressed user operation");
519
- const gasPriceParameters = await this.gasPriceManager.getGasPrice();
520
- childLogger.debug({ gasPriceParameters }, "got gas price");
521
- const nonce = await this.publicClient.getTransactionCount({
522
- address: wallet.address,
523
- blockTag: "pending"
524
- });
525
- childLogger.trace({ nonce }, "got nonce");
624
+ let nonce;
625
+ let gasPriceParameters;
626
+ try {
627
+ ;
628
+ [gasPriceParameters, nonce] = await Promise.all([
629
+ this.gasPriceManager.tryGetNetworkGasPrice(),
630
+ this.config.publicClient.getTransactionCount({
631
+ address: wallet.address,
632
+ blockTag: "pending"
633
+ })
634
+ ]);
635
+ }
636
+ catch (err) {
637
+ childLogger.error({ error: err }, "Failed to get parameters for bundling");
638
+ this.markWalletProcessed(wallet);
639
+ return compressedOps.map((compressedOp) => {
640
+ const userOpHash = getUserOperationHash(compressedOp.inflatedOp, entryPoint, this.config.walletClient.chain.id);
641
+ return {
642
+ status: "resubmit",
643
+ info: {
644
+ entryPoint,
645
+ userOpHash,
646
+ userOperation: compressedOp,
647
+ reason: "Failed to get parameters for bundling"
648
+ }
649
+ };
650
+ });
651
+ }
526
652
  const callContext = {
527
- publicClient: this.publicClient,
653
+ publicClient: this.config.publicClient,
528
654
  bundleBulker: compressionHandler.bundleBulkerAddress,
529
655
  perOpInflatorId: compressionHandler.perOpInflatorId,
530
656
  type: "compressed"
@@ -532,15 +658,15 @@ export class Executor {
532
658
  let { gasLimit, simulatedOps } = await filterOpsAndEstimateGas(entryPoint, callContext, wallet, compressedOps.map((compressedOp) => {
533
659
  return {
534
660
  mempoolUserOperation: compressedOp,
535
- userOperationHash: getUserOperationHash(compressedOp.inflatedOp, entryPoint, this.walletClient.chain.id)
661
+ userOperationHash: getUserOperationHash(compressedOp.inflatedOp, entryPoint, this.config.walletClient.chain.id)
536
662
  };
537
- }), nonce, gasPriceParameters.maxFeePerGas, gasPriceParameters.maxPriorityFeePerGas, this.blockTagSupport ? "pending" : undefined, this.legacyTransactions, this.fixedGasLimitForEstimation, this.reputationManager, childLogger);
663
+ }), nonce, gasPriceParameters.maxFeePerGas, gasPriceParameters.maxPriorityFeePerGas, this.config.blockTagSupport ? "pending" : undefined, this.config.legacyTransactions, this.config.fixedGasLimitForEstimation, this.reputationManager, childLogger);
538
664
  gasLimit += 10000n;
539
665
  if (simulatedOps.length === 0) {
540
666
  childLogger.warn("no ops to bundle");
541
667
  this.markWalletProcessed(wallet);
542
668
  return compressedOps.map((compressedOp) => {
543
- const userOpHash = getUserOperationHash(compressedOp.inflatedOp, entryPoint, this.walletClient.chain.id);
669
+ const userOpHash = getUserOperationHash(compressedOp.inflatedOp, entryPoint, this.config.walletClient.chain.id);
544
670
  return {
545
671
  status: "failure",
546
672
  error: {
@@ -573,7 +699,7 @@ export class Executor {
573
699
  .map((simulatedOp) => simulatedOp.owh);
574
700
  let transactionHash;
575
701
  try {
576
- const gasOptions = this.legacyTransactions
702
+ const gasOptions = this.config.legacyTransactions
577
703
  ? {
578
704
  gasPrice: gasPriceParameters.maxFeePerGas
579
705
  }
@@ -585,14 +711,12 @@ export class Executor {
585
711
  const compressedOp = mempoolUserOperation;
586
712
  return compressedOp;
587
713
  });
588
- // need to use sendTransaction to target BundleBulker's fallback
589
- transactionHash = await this.walletClient.sendTransaction({
590
- account: wallet,
591
- to: compressionHandler.bundleBulkerAddress,
592
- data: createCompressedCalldata(compressedOpsToBundle, compressionHandler.perOpInflatorId),
593
- gas: gasLimit,
594
- nonce: nonce,
595
- ...gasOptions
714
+ transactionHash = await this.sendHandleOpsTransaction({
715
+ txParam: {
716
+ type: "compressed",
717
+ compressedOps: compressedOpsToBundle
718
+ },
719
+ opts: { ...gasOptions, gas: gasLimit, account: wallet, nonce }
596
720
  });
597
721
  opsToBundle.map(({ userOperationHash }) => {
598
722
  this.eventManager.emitSubmitted(userOperationHash, transactionHash);
@@ -631,10 +755,9 @@ export class Executor {
631
755
  previousTransactionHashes: [],
632
756
  transactionRequest: {
633
757
  to: compressionHandler.bundleBulkerAddress,
634
- data: createCompressedCalldata(compressedOps, compressionHandler.perOpInflatorId),
635
758
  gas: gasLimit,
636
759
  account: wallet,
637
- chain: this.walletClient.chain,
760
+ chain: this.config.walletClient.chain,
638
761
  maxFeePerGas: gasPriceParameters.maxFeePerGas,
639
762
  maxPriorityFeePerGas: gasPriceParameters.maxPriorityFeePerGas,
640
763
  nonce: nonce