@@ -23,6 +23,7 @@ import {
2323 TRANSACTION_PRIORITY ,
2424 CONTRACT_FUNCTION_GAS_LIMIT_INCREASE_FACTORS ,
2525 ABIs ,
26+ EXPECTED_TRANSACTION_ERRORS ,
2627} from '../../../constants/constants.js' ;
2728import Web3ServiceValidator from './web3-service-validator.js' ;
2829
@@ -561,8 +562,10 @@ class Web3Service {
561562 operationalWallet ,
562563 ) {
563564 let result ;
564- const gasPrice = predefinedGasPrice ?? ( await this . getGasPrice ( ) ) ;
565+ let gasPrice = predefinedGasPrice ?? ( await this . getGasPrice ( ) ) ;
565566 let gasLimit ;
567+ let retryCount = 0 ;
568+ const maxRetries = 3 ;
566569
567570 try {
568571 /* eslint-disable no-await-in-loop */
@@ -577,33 +580,69 @@ class Web3Service {
577580
578581 gasLimit = gasLimit . mul ( gasLimitMultiplier * 100 ) . div ( 100 ) ;
579582
580- this . logger . debug (
581- `Sending signed transaction ${ functionName } to the blockchain ${ this . getBlockchainId ( ) } ` +
582- ` with gas limit: ${ gasLimit . toString ( ) } and gasPrice ${ gasPrice . toString ( ) } . ` +
583- `Transaction queue length: ${ this . getTotalTransactionQueueLength ( ) } . Wallet used: ${
584- operationalWallet . address
585- } `,
586- ) ;
583+ while ( retryCount < maxRetries ) {
584+ try {
585+ this . logger . debug (
586+ `Sending signed transaction ${ functionName } to the blockchain ${ this . getBlockchainId ( ) } ` +
587+ ` with gas limit: ${ gasLimit . toString ( ) } and gasPrice ${ gasPrice . toString ( ) } . ` +
588+ `Transaction queue length: ${ this . getTotalTransactionQueueLength ( ) } . Wallet used: ${
589+ operationalWallet . address
590+ } ${ retryCount > 0 ? ` (retry ${ retryCount } )` : '' } `,
591+ ) ;
587592
588- const tx = await contractInstance . connect ( operationalWallet ) [ functionName ] ( ...args , {
589- gasPrice,
590- gasLimit,
591- } ) ;
593+ const tx = await contractInstance
594+ . connect ( operationalWallet )
595+ [ functionName ] ( ...args , {
596+ gasPrice,
597+ gasLimit,
598+ } ) ;
592599
593- try {
594- result = await this . provider . waitForTransaction (
595- tx . hash ,
596- TRANSACTION_CONFIRMATIONS ,
597- TRANSACTION_POLLING_TIMEOUT_MILLIS ,
598- ) ;
600+ try {
601+ result = await this . provider . waitForTransaction (
602+ tx . hash ,
603+ TRANSACTION_CONFIRMATIONS ,
604+ TRANSACTION_POLLING_TIMEOUT_MILLIS ,
605+ ) ;
599606
600- if ( result . status === 0 ) {
601- await this . provider . call ( tx , tx . blockNumber ) ;
607+ if ( result . status === 0 ) {
608+ await this . provider . call ( tx , tx . blockNumber ) ;
609+ }
610+ } catch ( error ) {
611+ this . _decodeWaitForTxError ( contractInstance , functionName , error , args ) ;
612+ }
613+ return result ;
614+ } catch ( error ) {
615+ const errorMessage = error . message . toLowerCase ( ) ;
616+
617+ // Check for nonce-related errors
618+ if (
619+ errorMessage . includes (
620+ EXPECTED_TRANSACTION_ERRORS . NONCE_TOO_LOW . toLowerCase ( ) ,
621+ ) ||
622+ errorMessage . includes (
623+ EXPECTED_TRANSACTION_ERRORS . REPLACEMENT_UNDERPRICED . toLowerCase ( ) ,
624+ ) ||
625+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . ALREADY_KNOWN . toLowerCase ( ) )
626+ ) {
627+ retryCount += 1 ;
628+ if ( retryCount < maxRetries ) {
629+ // Increase gas price by 20% for nonce errors
630+ gasPrice = Math . ceil ( gasPrice * 1.2 ) ;
631+ this . logger . warn (
632+ `Nonce error detected for ${ functionName } . Retrying with increased gas price: ${ gasPrice } (retry ${ retryCount } /${ maxRetries } )` ,
633+ ) ;
634+ continue ;
635+ } else {
636+ this . logger . error (
637+ `Max retries (${ maxRetries } ) reached for nonce error in ${ functionName } . Final gas price: ${ gasPrice } ` ,
638+ ) ;
639+ }
640+ }
641+
642+ // If it's not a nonce error or we've exhausted retries, re-throw the error
643+ throw error ;
602644 }
603- } catch ( error ) {
604- this . _decodeWaitForTxError ( contractInstance , functionName , error , args ) ;
605645 }
606- return result ;
607646 }
608647
609648 _decodeEstimateGasError ( contractInstance , functionName , error , args ) {
0 commit comments