@@ -8,6 +8,9 @@ import type {
88import { Wallet } from "@ethersproject/wallet" ;
99import type { Wordlist } from "@ethersproject/wordlists" ;
1010
11+ import { Logger } from "@ethersproject/logger" ;
12+ const ethersLogger = new Logger ( "NonceKeeperWallet" ) ;
13+
1114import { log } from "./logger.js" ;
1215
1316const 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 ( / i n s u f f i c i e n t f u n d s | b a s e f e e e x c e e d s g a s l i m i t / 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 ( / n o n c e ( i s ) ? t o o l o w / 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 ( / r e p l a c e m e n t t r a n s a c t i o n u n d e r p r i c e d | t r a n s a c t i o n g a s p r i c e .* t o o l o w / 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 ( / o n l y r e p l a y - p r o t e c t e d / 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 ( / g a s r e q u i r e d e x c e e d s a l l o w a n c e | a l w a y s f a i l i n g t r a n s a c t i o n | e x e c u t i o n r e v e r t e d / ) ) {
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