@@ -210,7 +210,9 @@ const _sendUserOp = async (
210
210
} ) ;
211
211
accountFactoryAddress = getAddress ( onchainAccountFactoryAddress ) ;
212
212
} catch ( error ) {
213
- const errorMessage = `${ wrapError ( error , "RPC" ) . message } Failed to find factory address for account` ;
213
+ const errorMessage = `${
214
+ wrapError ( error , "RPC" ) . message
215
+ } Failed to find factory address for account`;
214
216
const erroredTransaction : ErroredTransaction = {
215
217
...queuedTransaction ,
216
218
status : "errored" ,
@@ -233,7 +235,9 @@ const _sendUserOp = async (
233
235
chain ,
234
236
) ;
235
237
} catch ( error ) {
236
- const errorMessage = `${ wrapError ( error , "RPC" ) . message } Failed to find entrypoint address for account factory` ;
238
+ const errorMessage = `${
239
+ wrapError ( error , "RPC" ) . message
240
+ } Failed to find entrypoint address for account factory`;
237
241
const erroredTransaction : ErroredTransaction = {
238
242
...queuedTransaction ,
239
243
status : "errored" ,
@@ -300,18 +304,36 @@ const _sendUserOp = async (
300
304
return erroredTransaction ;
301
305
}
302
306
307
+ // Handle if `gasFeeCeiling` is overridden.
308
+ // Delay the job if the estimated cost is higher than the gas fee ceiling.
309
+ const gasFeeCeiling = overrides ?. gasFeeCeiling ;
310
+ if ( typeof gasFeeCeiling !== "undefined" ) {
311
+ const estimatedCost =
312
+ unsignedUserOp . maxFeePerGas *
313
+ ( unsignedUserOp . callGasLimit +
314
+ unsignedUserOp . preVerificationGas +
315
+ unsignedUserOp . verificationGasLimit ) ;
316
+
317
+ if ( estimatedCost > gasFeeCeiling ) {
318
+ const retryAt = _minutesFromNow ( 5 ) ;
319
+ job . log (
320
+ `Override gas fee ceiling (${ gasFeeCeiling } ) is lower than onchain estimated cost (${ estimatedCost } ). Delaying job until ${ retryAt } . [callGasLimit: ${ unsignedUserOp . callGasLimit } , preVerificationGas: ${ unsignedUserOp . preVerificationGas } , verificationGasLimit: ${ unsignedUserOp . verificationGasLimit } , maxFeePerGas: ${ unsignedUserOp . maxFeePerGas } ]` ,
321
+ ) ;
322
+ // token is required to acquire lock for delaying currently processing job: https://docs.bullmq.io/patterns/process-step-jobs#delaying
323
+ await job . moveToDelayed ( retryAt . getTime ( ) , token ) ;
324
+ // throwing delayed error is required to notify bullmq worker not to complete or fail the job
325
+ throw new DelayedError ( "Delaying job due to gas fee override" ) ;
326
+ }
327
+ }
328
+
303
329
// Handle if `maxFeePerGas` is overridden.
304
330
// Set it if the transaction will be sent, otherwise delay the job.
305
- if (
306
- typeof overrides ?. maxFeePerGas !== "undefined" &&
307
- unsignedUserOp . maxFeePerGas
308
- ) {
309
- if ( overrides . maxFeePerGas > unsignedUserOp . maxFeePerGas ) {
310
- unsignedUserOp . maxFeePerGas = overrides . maxFeePerGas ;
311
- } else {
331
+ const overrideMaxFeePerGas = overrides ?. maxFeePerGas ;
332
+ if ( typeof overrideMaxFeePerGas !== "undefined" ) {
333
+ if ( unsignedUserOp . maxFeePerGas > overrideMaxFeePerGas ) {
312
334
const retryAt = _minutesFromNow ( 5 ) ;
313
335
job . log (
314
- `Override gas fee (${ overrides . maxFeePerGas } ) is lower than onchain fee (${ unsignedUserOp . maxFeePerGas } ). Delaying job until ${ retryAt } .` ,
336
+ `Override gas fee (${ overrideMaxFeePerGas } ) is lower than onchain fee (${ unsignedUserOp . maxFeePerGas } ). Delaying job until ${ retryAt } .` ,
315
337
) ;
316
338
// token is required to acquire lock for delaying currently processing job: https://docs.bullmq.io/patterns/process-step-jobs#delaying
317
339
await job . moveToDelayed ( retryAt . getTime ( ) , token ) ;
@@ -331,7 +353,9 @@ const _sendUserOp = async (
331
353
userOp : unsignedUserOp ,
332
354
} ) ;
333
355
} catch ( error ) {
334
- const errorMessage = `${ wrapError ( error , "Bundler" ) . message } Failed to sign prepared userop` ;
356
+ const errorMessage = `${
357
+ wrapError ( error , "Bundler" ) . message
358
+ } Failed to sign prepared userop`;
335
359
const erroredTransaction : ErroredTransaction = {
336
360
...queuedTransaction ,
337
361
status : "errored" ,
@@ -356,7 +380,9 @@ const _sendUserOp = async (
356
380
} ,
357
381
} ) ;
358
382
} catch ( error ) {
359
- const errorMessage = `${ wrapError ( error , "Bundler" ) . message } Failed to bundle userop` ;
383
+ const errorMessage = `${
384
+ wrapError ( error , "Bundler" ) . message
385
+ } Failed to bundle userop`;
360
386
const erroredTransaction : ErroredTransaction = {
361
387
...queuedTransaction ,
362
388
status : "errored" ,
@@ -478,6 +504,32 @@ const _sendTransaction = async (
478
504
}
479
505
}
480
506
507
+ // Handle if `gasFeeCeiling` is overridden.
508
+ // Delay the job if the estimated cost is higher than the gas fee ceiling.
509
+ const gasFeeCeiling = overrides ?. gasFeeCeiling ;
510
+ if ( typeof gasFeeCeiling !== "undefined" ) {
511
+ let estimatedCost = 0n ;
512
+
513
+ if ( populatedTransaction . maxFeePerGas ) {
514
+ estimatedCost =
515
+ populatedTransaction . maxFeePerGas * populatedTransaction . gas ;
516
+ } else if ( populatedTransaction . gasPrice ) {
517
+ estimatedCost = populatedTransaction . gas * populatedTransaction . gasPrice ;
518
+ }
519
+
520
+ // in case neither of the estimations work, the estimatedCost will be 0n, so this check should not pass, and transaction remains unaffected
521
+ if ( estimatedCost > gasFeeCeiling ) {
522
+ const retryAt = _minutesFromNow ( 5 ) ;
523
+ job . log (
524
+ `Override gas fee ceiling (${ gasFeeCeiling } ) is lower than onchain estimated cost (${ estimatedCost } ). Delaying job until ${ retryAt } . [gas: ${ populatedTransaction . gas } , gasPrice: ${ populatedTransaction . gasPrice } , maxFeePerGas: ${ populatedTransaction . maxFeePerGas } ]` ,
525
+ ) ;
526
+ // token is required to acquire lock for delaying currently processing job: https://docs.bullmq.io/patterns/process-step-jobs#delaying
527
+ await job . moveToDelayed ( retryAt . getTime ( ) , token ) ;
528
+ // throwing delayed error is required to notify bullmq worker not to complete or fail the job
529
+ throw new DelayedError ( "Delaying job due to gas fee override" ) ;
530
+ }
531
+ }
532
+
481
533
// Acquire an unused nonce for this transaction.
482
534
const { nonce, isRecycledNonce } = await acquireNonce ( {
483
535
queueId,
@@ -495,8 +547,9 @@ const _sendTransaction = async (
495
547
// This call throws if the RPC rejects the transaction.
496
548
let transactionHash : Hex ;
497
549
try {
498
- const sendTransactionResult =
499
- await account . sendTransaction ( populatedTransaction ) ;
550
+ const sendTransactionResult = await account . sendTransaction (
551
+ populatedTransaction ,
552
+ ) ;
500
553
transactionHash = sendTransactionResult . transactionHash ;
501
554
} catch ( error : unknown ) {
502
555
// If the nonce is already seen onchain (nonce too low) or in mempool (replacement underpriced),
0 commit comments