@atomiqlabs/chain-evm 1.0.0-dev.68 → 1.0.0-dev.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/evm/chain/modules/EVMTransactions.js +10 -5
- package/dist/evm/providers/JsonRpcProviderWithRetries.js +2 -2
- package/dist/evm/providers/WebSocketProviderWithRetries.js +2 -2
- package/dist/evm/wallet/EVMPersistentSigner.js +11 -3
- package/dist/utils/Utils.d.ts +1 -0
- package/dist/utils/Utils.js +7 -1
- package/package.json +1 -1
- package/src/evm/chain/modules/EVMTransactions.ts +14 -7
- package/src/evm/providers/JsonRpcProviderWithRetries.ts +3 -5
- package/src/evm/providers/WebSocketProviderWithRetries.ts +2 -3
- package/src/evm/wallet/EVMPersistentSigner.ts +9 -3
- package/src/utils/Utils.ts +7 -0
|
@@ -31,12 +31,15 @@ class EVMTransactions extends EVMModule_1.EVMModule {
|
|
|
31
31
|
};
|
|
32
32
|
this.onBeforeTxReplace(txReplaceListener);
|
|
33
33
|
let state = "pending";
|
|
34
|
+
let confirmedTxId = null;
|
|
34
35
|
while (state === "pending" || state === "not_found") {
|
|
35
36
|
await (0, Utils_1.timeoutPromise)(3000, abortSignal);
|
|
36
37
|
for (let txId of checkTxns) {
|
|
37
38
|
state = await this.getTxIdStatus(txId);
|
|
38
|
-
if (state === "reverted" || state === "success")
|
|
39
|
+
if (state === "reverted" || state === "success") {
|
|
40
|
+
confirmedTxId = txId;
|
|
39
41
|
break;
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
this.offBeforeTxReplace(txReplaceListener);
|
|
@@ -47,6 +50,7 @@ class EVMTransactions extends EVMModule_1.EVMModule {
|
|
|
47
50
|
}
|
|
48
51
|
if (state === "reverted")
|
|
49
52
|
throw new Error("Transaction reverted!");
|
|
53
|
+
return confirmedTxId;
|
|
50
54
|
}
|
|
51
55
|
/**
|
|
52
56
|
* Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed & calls beforeTxSigned callback
|
|
@@ -138,7 +142,7 @@ class EVMTransactions extends EVMModule_1.EVMModule {
|
|
|
138
142
|
}
|
|
139
143
|
this.logger.debug("sendAndConfirm(): sending transactions, count: " + txs.length +
|
|
140
144
|
" waitForConfirmation: " + waitForConfirmation + " parallel: " + parallel);
|
|
141
|
-
|
|
145
|
+
let txIds = [];
|
|
142
146
|
if (parallel) {
|
|
143
147
|
let promises = [];
|
|
144
148
|
for (let i = 0; i < txs.length; i++) {
|
|
@@ -166,7 +170,7 @@ class EVMTransactions extends EVMModule_1.EVMModule {
|
|
|
166
170
|
}
|
|
167
171
|
}
|
|
168
172
|
if (promises.length > 0)
|
|
169
|
-
await Promise.all(promises);
|
|
173
|
+
txIds = await Promise.all(promises);
|
|
170
174
|
}
|
|
171
175
|
else {
|
|
172
176
|
for (let i = 0; i < txs.length; i++) {
|
|
@@ -187,9 +191,10 @@ class EVMTransactions extends EVMModule_1.EVMModule {
|
|
|
187
191
|
const confirmPromise = this.confirmTransaction(tx, abortSignal);
|
|
188
192
|
this.logger.debug("sendAndConfirm(): transaction sent (" + (i + 1) + "/" + txs.length + "): " + tx.hash);
|
|
189
193
|
//Don't await the last promise when !waitForConfirmation
|
|
194
|
+
let txHash = tx.hash;
|
|
190
195
|
if (i < txs.length - 1 || waitForConfirmation)
|
|
191
|
-
await confirmPromise;
|
|
192
|
-
txIds.push(
|
|
196
|
+
txHash = await confirmPromise;
|
|
197
|
+
txIds.push(txHash);
|
|
193
198
|
}
|
|
194
199
|
}
|
|
195
200
|
this.logger.info("sendAndConfirm(): sent transactions, count: " + txs.length +
|
|
@@ -10,9 +10,9 @@ class JsonRpcProviderWithRetries extends ethers_1.JsonRpcProvider {
|
|
|
10
10
|
}
|
|
11
11
|
send(method, params) {
|
|
12
12
|
return (0, Utils_1.tryWithRetries)(() => super.send(method, params), this.retryPolicy, e => {
|
|
13
|
+
if (e.code != null && typeof (e.code) === "string")
|
|
14
|
+
return Utils_1.allowedEthersErrorCodes.has(e.code);
|
|
13
15
|
return false;
|
|
14
|
-
// if(e?.error?.code!=null) return false; //Error returned by the RPC
|
|
15
|
-
// return true;
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -10,9 +10,9 @@ class WebSocketProviderWithRetries extends ReconnectingWebSocketProvider_1.Recon
|
|
|
10
10
|
}
|
|
11
11
|
send(method, params) {
|
|
12
12
|
return (0, Utils_1.tryWithRetries)(() => super.send(method, params), this.retryPolicy, e => {
|
|
13
|
+
if (e.code != null && typeof (e.code) === "string")
|
|
14
|
+
return Utils_1.allowedEthersErrorCodes.has(e.code);
|
|
13
15
|
return false;
|
|
14
|
-
// if(e?.error?.code!=null) return false; //Error returned by the RPC
|
|
15
|
-
// return true;
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -98,7 +98,11 @@ class EVMPersistentSigner extends EVMSigner_1.EVMSigner {
|
|
|
98
98
|
priorityFee > (this.minFeeIncreaseAbsolute + (_gasPrice.priorityFee * (1000000n + this.minFeeIncreasePpm) / 1000000n))) {
|
|
99
99
|
//Too big of an increase over the current fee rate, don't fee bump
|
|
100
100
|
this.logger.debug("checkPastTransactions(): Tx yet unconfirmed but not increasing fee for ", lastTx.hash);
|
|
101
|
-
await this.chainInterface.provider.broadcastTransaction(lastTx.serialized).catch(e =>
|
|
101
|
+
await this.chainInterface.provider.broadcastTransaction(lastTx.serialized).catch(e => {
|
|
102
|
+
if (e.code === "NONCE_EXPIRED")
|
|
103
|
+
return;
|
|
104
|
+
this.logger.error("checkPastTransactions(): Tx re-broadcast error", e);
|
|
105
|
+
});
|
|
102
106
|
continue;
|
|
103
107
|
}
|
|
104
108
|
let newTx = lastTx.clone();
|
|
@@ -112,7 +116,7 @@ class EVMPersistentSigner extends EVMSigner_1.EVMSigner {
|
|
|
112
116
|
newTx = ethers_1.Transaction.from(signedRawTx);
|
|
113
117
|
for (let callback of this.chainInterface.Transactions._cbksBeforeTxReplace) {
|
|
114
118
|
try {
|
|
115
|
-
await callback(lastTx.
|
|
119
|
+
await callback(lastTx.serialized, lastTx.hash, signedRawTx, newTx.hash);
|
|
116
120
|
}
|
|
117
121
|
catch (e) {
|
|
118
122
|
this.logger.error("checkPastTransactions(): beforeTxReplace callback error: ", e);
|
|
@@ -123,7 +127,11 @@ class EVMPersistentSigner extends EVMSigner_1.EVMSigner {
|
|
|
123
127
|
this.save();
|
|
124
128
|
this.chainInterface.Transactions._knownTxSet.add(newTx.hash);
|
|
125
129
|
//TODO: Better error handling when sending tx
|
|
126
|
-
await this.chainInterface.provider.broadcastTransaction(signedRawTx).catch(e =>
|
|
130
|
+
await this.chainInterface.provider.broadcastTransaction(signedRawTx).catch(e => {
|
|
131
|
+
if (e.code === "NONCE_EXPIRED")
|
|
132
|
+
return;
|
|
133
|
+
this.logger.error("checkPastTransactions(): Fee-bumped tx broadcast error", e);
|
|
134
|
+
});
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
137
|
}
|
package/dist/utils/Utils.d.ts
CHANGED
|
@@ -14,3 +14,4 @@ export declare function tryWithRetries<T>(func: () => Promise<T>, retryPolicy?:
|
|
|
14
14
|
}, errorAllowed?: (e: any) => boolean, abortSignal?: AbortSignal): Promise<T>;
|
|
15
15
|
export declare function uint32ReverseEndianness(value: number): number;
|
|
16
16
|
export declare function bigIntMax(a: bigint, b: bigint): bigint;
|
|
17
|
+
export declare const allowedEthersErrorCodes: Set<string>;
|
package/dist/utils/Utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.bigIntMax = exports.uint32ReverseEndianness = exports.tryWithRetries = exports.getLogger = exports.onceAsync = exports.timeoutPromise = void 0;
|
|
3
|
+
exports.allowedEthersErrorCodes = exports.bigIntMax = exports.uint32ReverseEndianness = exports.tryWithRetries = exports.getLogger = exports.onceAsync = exports.timeoutPromise = void 0;
|
|
4
4
|
function timeoutPromise(timeoutMillis, abortSignal) {
|
|
5
5
|
return new Promise((resolve, reject) => {
|
|
6
6
|
const timeout = setTimeout(resolve, timeoutMillis);
|
|
@@ -73,3 +73,9 @@ function bigIntMax(a, b) {
|
|
|
73
73
|
return a > b ? a : b;
|
|
74
74
|
}
|
|
75
75
|
exports.bigIntMax = bigIntMax;
|
|
76
|
+
exports.allowedEthersErrorCodes = new Set([
|
|
77
|
+
"NOT_IMPLEMENTED", "UNSUPPORTED_OPERATION", "BAD_DATA",
|
|
78
|
+
"NUMERIC_FAULT",
|
|
79
|
+
"INVALID_ARGUMENT", "MISSING_ARGUMENT", "UNEXPECTED_ARGUMENT", "VALUE_MISMATCH",
|
|
80
|
+
"CALL_EXCEPTION", "NONCE_EXPIRED", "REPLACEMENT_UNDERPRICED", "TRANSACTION_REPLACED", "UNCONFIGURED_NAME", "OFFCHAIN_FAULT", "ACTION_REJECTED"
|
|
81
|
+
]);
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@ export class EVMTransactions extends EVMModule<any> {
|
|
|
39
39
|
* @param abortSignal signal to abort waiting for tx confirmation
|
|
40
40
|
* @private
|
|
41
41
|
*/
|
|
42
|
-
private async confirmTransaction(tx: TransactionResponse | Transaction, abortSignal?: AbortSignal) {
|
|
42
|
+
private async confirmTransaction(tx: TransactionResponse | Transaction, abortSignal?: AbortSignal): Promise<string> {
|
|
43
43
|
const checkTxns: Set<string> = new Set([tx.hash]);
|
|
44
44
|
|
|
45
45
|
const txReplaceListener = (oldTx: string, oldTxId: string, newTx: string, newTxId: string) => {
|
|
@@ -49,11 +49,15 @@ export class EVMTransactions extends EVMModule<any> {
|
|
|
49
49
|
this.onBeforeTxReplace(txReplaceListener);
|
|
50
50
|
|
|
51
51
|
let state = "pending";
|
|
52
|
+
let confirmedTxId: string = null;
|
|
52
53
|
while(state==="pending" || state==="not_found") {
|
|
53
54
|
await timeoutPromise(3000, abortSignal);
|
|
54
55
|
for(let txId of checkTxns) {
|
|
55
56
|
state = await this.getTxIdStatus(txId);
|
|
56
|
-
if(state==="reverted" || state==="success")
|
|
57
|
+
if(state==="reverted" || state==="success") {
|
|
58
|
+
confirmedTxId = txId;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
@@ -65,6 +69,8 @@ export class EVMTransactions extends EVMModule<any> {
|
|
|
65
69
|
this.latestConfirmedNonces[tx.from] = nextAccountNonce;
|
|
66
70
|
}
|
|
67
71
|
if(state==="reverted") throw new Error("Transaction reverted!");
|
|
72
|
+
|
|
73
|
+
return confirmedTxId;
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
/**
|
|
@@ -168,9 +174,9 @@ export class EVMTransactions extends EVMModule<any> {
|
|
|
168
174
|
this.logger.debug("sendAndConfirm(): sending transactions, count: "+txs.length+
|
|
169
175
|
" waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
|
|
170
176
|
|
|
171
|
-
|
|
177
|
+
let txIds: string[] = [];
|
|
172
178
|
if(parallel) {
|
|
173
|
-
let promises: Promise<
|
|
179
|
+
let promises: Promise<string>[] = [];
|
|
174
180
|
for(let i=0;i<txs.length;i++) {
|
|
175
181
|
let tx: TransactionResponse | Transaction;
|
|
176
182
|
if(signer.signTransaction==null) {
|
|
@@ -195,7 +201,7 @@ export class EVMTransactions extends EVMModule<any> {
|
|
|
195
201
|
promises = [];
|
|
196
202
|
}
|
|
197
203
|
}
|
|
198
|
-
if(promises.length>0) await Promise.all(promises);
|
|
204
|
+
if(promises.length>0) txIds = await Promise.all(promises);
|
|
199
205
|
} else {
|
|
200
206
|
for(let i=0;i<txs.length;i++) {
|
|
201
207
|
let tx: TransactionResponse | Transaction;
|
|
@@ -216,8 +222,9 @@ export class EVMTransactions extends EVMModule<any> {
|
|
|
216
222
|
const confirmPromise = this.confirmTransaction(tx, abortSignal);
|
|
217
223
|
this.logger.debug("sendAndConfirm(): transaction sent ("+(i+1)+"/"+txs.length+"): "+tx.hash);
|
|
218
224
|
//Don't await the last promise when !waitForConfirmation
|
|
219
|
-
|
|
220
|
-
|
|
225
|
+
let txHash = tx.hash;
|
|
226
|
+
if(i<txs.length-1 || waitForConfirmation) txHash = await confirmPromise;
|
|
227
|
+
txIds.push(txHash);
|
|
221
228
|
}
|
|
222
229
|
}
|
|
223
230
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {JsonRpcProvider, JsonRpcApiProviderOptions} from "ethers";
|
|
1
|
+
import {JsonRpcProvider, JsonRpcApiProviderOptions, makeError} from "ethers";
|
|
2
2
|
import type {Networkish, FetchRequest} from "ethers";
|
|
3
|
-
import {tryWithRetries} from "../../utils/Utils";
|
|
4
|
-
|
|
3
|
+
import {allowedEthersErrorCodes, tryWithRetries} from "../../utils/Utils";
|
|
5
4
|
|
|
6
5
|
export class JsonRpcProviderWithRetries extends JsonRpcProvider {
|
|
7
6
|
|
|
@@ -18,9 +17,8 @@ export class JsonRpcProviderWithRetries extends JsonRpcProvider {
|
|
|
18
17
|
|
|
19
18
|
send(method: string, params: Array<any> | Record<string, any>): Promise<any> {
|
|
20
19
|
return tryWithRetries(() => super.send(method, params), this.retryPolicy, e => {
|
|
20
|
+
if(e.code!=null && typeof(e.code)==="string") return allowedEthersErrorCodes.has(e.code);
|
|
21
21
|
return false;
|
|
22
|
-
// if(e?.error?.code!=null) return false; //Error returned by the RPC
|
|
23
|
-
// return true;
|
|
24
22
|
});
|
|
25
23
|
}
|
|
26
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {JsonRpcApiProviderOptions} from "ethers";
|
|
2
2
|
import type {Networkish} from "ethers";
|
|
3
|
-
import {tryWithRetries} from "../../utils/Utils";
|
|
3
|
+
import {allowedEthersErrorCodes, tryWithRetries} from "../../utils/Utils";
|
|
4
4
|
import {ReconnectingWebSocketProvider} from "./ReconnectingWebSocketProvider";
|
|
5
5
|
import type {WebSocketLike} from "ethers/lib.esm";
|
|
6
6
|
|
|
@@ -20,9 +20,8 @@ export class WebSocketProviderWithRetries extends ReconnectingWebSocketProvider
|
|
|
20
20
|
|
|
21
21
|
send(method: string, params: Array<any> | Record<string, any>): Promise<any> {
|
|
22
22
|
return tryWithRetries(() => super.send(method, params), this.retryPolicy, e => {
|
|
23
|
+
if(e.code!=null && typeof(e.code)==="string") return allowedEthersErrorCodes.has(e.code);
|
|
23
24
|
return false;
|
|
24
|
-
// if(e?.error?.code!=null) return false; //Error returned by the RPC
|
|
25
|
-
// return true;
|
|
26
25
|
});
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -160,7 +160,10 @@ export class EVMPersistentSigner extends EVMSigner {
|
|
|
160
160
|
) {
|
|
161
161
|
//Too big of an increase over the current fee rate, don't fee bump
|
|
162
162
|
this.logger.debug("checkPastTransactions(): Tx yet unconfirmed but not increasing fee for ", lastTx.hash);
|
|
163
|
-
await this.chainInterface.provider.broadcastTransaction(lastTx.serialized).catch(e =>
|
|
163
|
+
await this.chainInterface.provider.broadcastTransaction(lastTx.serialized).catch(e => {
|
|
164
|
+
if(e.code==="NONCE_EXPIRED") return;
|
|
165
|
+
this.logger.error("checkPastTransactions(): Tx re-broadcast error", e)
|
|
166
|
+
});
|
|
164
167
|
continue;
|
|
165
168
|
}
|
|
166
169
|
|
|
@@ -178,7 +181,7 @@ export class EVMPersistentSigner extends EVMSigner {
|
|
|
178
181
|
|
|
179
182
|
for(let callback of this.chainInterface.Transactions._cbksBeforeTxReplace) {
|
|
180
183
|
try {
|
|
181
|
-
await callback(lastTx.
|
|
184
|
+
await callback(lastTx.serialized, lastTx.hash, signedRawTx, newTx.hash)
|
|
182
185
|
} catch (e) {
|
|
183
186
|
this.logger.error("checkPastTransactions(): beforeTxReplace callback error: ", e);
|
|
184
187
|
}
|
|
@@ -191,7 +194,10 @@ export class EVMPersistentSigner extends EVMSigner {
|
|
|
191
194
|
this.chainInterface.Transactions._knownTxSet.add(newTx.hash);
|
|
192
195
|
|
|
193
196
|
//TODO: Better error handling when sending tx
|
|
194
|
-
await this.chainInterface.provider.broadcastTransaction(signedRawTx).catch(e =>
|
|
197
|
+
await this.chainInterface.provider.broadcastTransaction(signedRawTx).catch(e => {
|
|
198
|
+
if(e.code==="NONCE_EXPIRED") return;
|
|
199
|
+
this.logger.error("checkPastTransactions(): Fee-bumped tx broadcast error", e)
|
|
200
|
+
});
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
}
|
package/src/utils/Utils.ts
CHANGED
|
@@ -83,3 +83,10 @@ export function uint32ReverseEndianness(value: number): number {
|
|
|
83
83
|
export function bigIntMax(a: bigint, b: bigint) {
|
|
84
84
|
return a>b ? a : b;
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
export const allowedEthersErrorCodes: Set<string> = new Set([
|
|
88
|
+
"NOT_IMPLEMENTED", "UNSUPPORTED_OPERATION", "BAD_DATA",
|
|
89
|
+
"NUMERIC_FAULT",
|
|
90
|
+
"INVALID_ARGUMENT", "MISSING_ARGUMENT", "UNEXPECTED_ARGUMENT", "VALUE_MISMATCH",
|
|
91
|
+
"CALL_EXCEPTION", "NONCE_EXPIRED", "REPLACEMENT_UNDERPRICED", "TRANSACTION_REPLACED", "UNCONFIGURED_NAME", "OFFCHAIN_FAULT", "ACTION_REJECTED"
|
|
92
|
+
]);
|