@@ -522,6 +522,10 @@ class Web3Service {
522522 }
523523 }
524524
525+ buildTransactionGasParams ( gasPrice ) {
526+ return { gasPrice } ;
527+ }
528+
525529 async callContractFunction ( contractInstance , functionName , args , contractName = null ) {
526530 const maxNumberOfRetries = 3 ;
527531 const retryDelayInSec = 12 ;
@@ -567,11 +571,35 @@ class Web3Service {
567571 let retryCount = 0 ;
568572 const maxRetries = 3 ;
569573
570- try {
571- /* eslint-disable no-await-in-loop */
572- gasLimit = await contractInstance . estimateGas [ functionName ] ( ...args ) ;
573- } catch ( error ) {
574- this . _decodeEstimateGasError ( contractInstance , functionName , error , args ) ;
574+ for ( let estimateAttempt = 0 ; estimateAttempt < 3 ; estimateAttempt += 1 ) {
575+ try {
576+ /* eslint-disable no-await-in-loop */
577+ gasLimit = await contractInstance . estimateGas [ functionName ] ( ...args ) ;
578+ break ;
579+ } catch ( error ) {
580+ const errMsg = error . message ?. toLowerCase ( ) ?? '' ;
581+ const isTransient =
582+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . EXECUTION_FAILED . toLowerCase ( ) ) ||
583+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . FEE_TOO_LOW . toLowerCase ( ) ) ||
584+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . SOCKET_HANG_UP ) ||
585+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . ECONNRESET ) ||
586+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . ECONNREFUSED ) ||
587+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . SERVER_ERROR ) ||
588+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . BAD_GATEWAY ) ||
589+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . SERVICE_UNAVAILABLE ) ||
590+ errMsg . includes ( EXPECTED_TRANSACTION_ERRORS . EXPECT_BLOCK_NUMBER ) ;
591+ if ( isTransient && estimateAttempt < 2 ) {
592+ this . logger . warn (
593+ `Gas estimation for ${ functionName } failed with transient error on ${ this . getBlockchainId ( ) } , ` +
594+ `retrying (${ estimateAttempt + 1 } /3): ${ error . message } ` ,
595+ ) ;
596+ await new Promise ( ( r ) => {
597+ setTimeout ( r , 2000 ) ;
598+ } ) ;
599+ continue ;
600+ }
601+ this . _decodeEstimateGasError ( contractInstance , functionName , error , args ) ;
602+ }
575603 }
576604
577605 gasLimit = gasLimit ?? ethers . utils . parseUnits ( '900' , 'kwei' ) ;
@@ -590,12 +618,12 @@ class Web3Service {
590618 } ${ retryCount > 0 ? ` (retry ${ retryCount } )` : '' } `,
591619 ) ;
592620
621+ const txOverrides = this . buildTransactionGasParams ( gasPrice ) ;
622+ txOverrides . gasLimit = gasLimit ;
623+
593624 const tx = await contractInstance
594625 . connect ( operationalWallet )
595- [ functionName ] ( ...args , {
596- gasPrice,
597- gasLimit,
598- } ) ;
626+ [ functionName ] ( ...args , txOverrides ) ;
599627
600628 try {
601629 result = await this . provider . waitForTransaction (
@@ -644,22 +672,41 @@ class Web3Service {
644672 EXPECTED_TRANSACTION_ERRORS . TIMEOUT_EXCEEDED . toLowerCase ( ) ,
645673 ) ;
646674
647- if ( isNonceError || isTimeoutError ) {
675+ const isExecutionError =
676+ errorMessage . includes (
677+ EXPECTED_TRANSACTION_ERRORS . EXECUTION_FAILED . toLowerCase ( ) ,
678+ ) ||
679+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . FEE_TOO_LOW . toLowerCase ( ) ) ;
680+
681+ const isNetworkError =
682+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . SOCKET_HANG_UP ) ||
683+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . ECONNRESET ) ||
684+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . ECONNREFUSED ) ||
685+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . SERVER_ERROR ) ||
686+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . BAD_GATEWAY ) ||
687+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . SERVICE_UNAVAILABLE ) ||
688+ errorMessage . includes ( EXPECTED_TRANSACTION_ERRORS . EXPECT_BLOCK_NUMBER ) ;
689+
690+ if ( isNonceError || isTimeoutError || isExecutionError || isNetworkError ) {
648691 retryCount += 1 ;
649692 if ( retryCount < maxRetries ) {
650693 gasPrice = Math . ceil ( gasPrice * 1.2 ) ;
694+ let errorType = 'Nonce' ;
695+ if ( isTimeoutError ) errorType = 'Timeout' ;
696+ else if ( isExecutionError ) errorType = 'Execution/fee' ;
697+ else if ( isNetworkError ) errorType = 'Network' ;
651698 this . logger . warn (
652- `${
653- isTimeoutError ? 'Timeout' : 'Nonce'
654- } error detected for ${ functionName } on ${ this . getBlockchainId ( ) } . ` +
699+ `${ errorType } error detected for ${ functionName } on ${ this . getBlockchainId ( ) } . ` +
655700 `Retrying with increased gas price: ${ gasPrice } (retry ${ retryCount } /${ maxRetries } )` ,
656701 ) ;
657702 continue ;
658703 }
704+ let errorType = 'nonce' ;
705+ if ( isTimeoutError ) errorType = 'timeout' ;
706+ else if ( isExecutionError ) errorType = 'execution/fee' ;
707+ else if ( isNetworkError ) errorType = 'network' ;
659708 this . logger . error (
660- `Max retries (${ maxRetries } ) reached for ${
661- isTimeoutError ? 'timeout' : 'nonce'
662- } error in ${ functionName } on ${ this . getBlockchainId ( ) } . ` +
709+ `Max retries (${ maxRetries } ) reached for ${ errorType } error in ${ functionName } on ${ this . getBlockchainId ( ) } . ` +
663710 `Final gas price: ${ gasPrice } ` ,
664711 ) ;
665712 }
0 commit comments