Skip to content

Commit 3cc7a77

Browse files
committed
fix gnosis and base errors
1 parent 49a7614 commit 3cc7a77

3 files changed

Lines changed: 87 additions & 16 deletions

File tree

src/constants/constants.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,15 @@ export const EXPECTED_TRANSACTION_ERRORS = {
715715
NONCE_TOO_LOW: 'nonce too low',
716716
REPLACEMENT_UNDERPRICED: 'replacement transaction underpriced',
717717
ALREADY_KNOWN: 'already known',
718+
EXECUTION_FAILED: 'transaction execution fails',
719+
FEE_TOO_LOW: 'feetoolow',
720+
SOCKET_HANG_UP: 'socket hang up',
721+
ECONNRESET: 'econnreset',
722+
ECONNREFUSED: 'econnrefused',
723+
SERVER_ERROR: 'server error',
724+
BAD_GATEWAY: '502',
725+
SERVICE_UNAVAILABLE: '503',
726+
EXPECT_BLOCK_NUMBER: 'expect block number from id',
718727
};
719728

720729
/**

src/modules/blockchain/implementation/gnosis/gnosis-service.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,21 @@ class GnosisService extends Web3Service {
5454
return this.defaultGasPrice;
5555
}
5656

57+
buildTransactionGasParams(gasPrice) {
58+
const maxFeePerGas = gasPrice;
59+
const minPriorityFee = ethers.BigNumber.from(2_000_000_000);
60+
61+
let maxPriorityFeePerGas = minPriorityFee;
62+
if (ethers.BigNumber.isBigNumber(gasPrice)) {
63+
const derived = gasPrice.div(5);
64+
if (derived.gt(minPriorityFee)) {
65+
maxPriorityFeePerGas = derived;
66+
}
67+
}
68+
69+
return { maxFeePerGas, maxPriorityFeePerGas };
70+
}
71+
5772
async healthCheck() {
5873
try {
5974
const blockNumber = await this.getBlockNumber();

src/modules/blockchain/implementation/web3-service.js

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)