Skip to content

Commit d6ba685

Browse files
authored
Merge pull request #121 from BootNodeDev/fantom-nonce
fix: phantom nonce generation
2 parents ad9ea05 + 4d6777e commit d6ba685

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

typescript/solver/NonceKeeperWallet.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import type {
88
import { Wallet } from "@ethersproject/wallet";
99
import type { Wordlist } from "@ethersproject/wordlists";
1010

11+
import { Logger } from "@ethersproject/logger";
12+
const ethersLogger = new Logger("NonceKeeperWallet");
13+
1114
import { log } from "./logger.js";
1215

1316
const nonces: Record<number, Promise<number>> = {};
@@ -29,6 +32,13 @@ export class NonceKeeperWallet extends Wallet {
2932
async sendTransaction(
3033
transaction: Deferrable<TransactionRequest>,
3134
): Promise<TransactionResponse> {
35+
try {
36+
// this check is necessary in order to not generate new nonces when a tx is going to fail
37+
await super.estimateGas(transaction);
38+
} catch (error) {
39+
checkError(error, {transaction});
40+
}
41+
3242
if (transaction.nonce == null) {
3343
transaction.nonce = await this.getNextNonce();
3444
}
@@ -52,3 +62,53 @@ export class NonceKeeperWallet extends Wallet {
5262
);
5363
}
5464
}
65+
66+
function checkError(error: any, params: any): any {
67+
const transaction = params.transaction || params.signedTransaction;
68+
69+
let message = error.message;
70+
if (error.code === Logger.errors.SERVER_ERROR && error.error && typeof(error.error.message) === "string") {
71+
message = error.error.message;
72+
} else if (typeof(error.body) === "string") {
73+
message = error.body;
74+
} else if (typeof(error.responseText) === "string") {
75+
message = error.responseText;
76+
}
77+
message = (message || "").toLowerCase();
78+
79+
// "insufficient funds for gas * price + value + cost(data)"
80+
if (message.match(/insufficient funds|base fee exceeds gas limit/i)) {
81+
ethersLogger.throwError("insufficient funds for intrinsic transaction cost", Logger.errors.INSUFFICIENT_FUNDS, {
82+
error, transaction
83+
});
84+
}
85+
86+
// "nonce too low"
87+
if (message.match(/nonce (is )?too low/i)) {
88+
ethersLogger.throwError("nonce has already been used", Logger.errors.NONCE_EXPIRED, {
89+
error, transaction
90+
});
91+
}
92+
93+
// "replacement transaction underpriced"
94+
if (message.match(/replacement transaction underpriced|transaction gas price.*too low/i)) {
95+
ethersLogger.throwError("replacement fee too low", Logger.errors.REPLACEMENT_UNDERPRICED, {
96+
error, transaction
97+
});
98+
}
99+
100+
// "replacement transaction underpriced"
101+
if (message.match(/only replay-protected/i)) {
102+
ethersLogger.throwError("legacy pre-eip-155 transactions not supported", Logger.errors.UNSUPPORTED_OPERATION, {
103+
error, transaction
104+
});
105+
}
106+
107+
if (message.match(/gas required exceeds allowance|always failing transaction|execution reverted/)) {
108+
ethersLogger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
109+
error, transaction
110+
});
111+
}
112+
113+
throw error;
114+
}

0 commit comments

Comments
 (0)