@atomiqlabs/chain-solana 13.5.11 → 13.5.12
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.
|
@@ -50,18 +50,23 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
|
|
|
50
50
|
watchdogInterval = setInterval(async () => {
|
|
51
51
|
const result = await this.sendRawTransaction(rawTx, { skipPreflight: true }).catch(e => this.logger.error("txConfirmationAndResendWatchdog(): transaction re-sent error: ", e));
|
|
52
52
|
this.logger.debug("txConfirmationAndResendWatchdog(): transaction re-sent: " + result);
|
|
53
|
-
|
|
53
|
+
let status = await this.getTxIdStatus(signature, finality).catch(e => this.logger.error("txConfirmationAndResendWatchdog(): get tx id status error: ", e));
|
|
54
54
|
if (status == null || status === "not_found") {
|
|
55
|
-
|
|
55
|
+
const blockValidity = await this.connection.isBlockhashValid(tx.recentBlockhash, { commitment: finality }).catch(e => this.logger.error("txConfirmationAndResendWatchdog(): blockhash validity check error: ", e));
|
|
56
|
+
if (!blockValidity)
|
|
57
|
+
return;
|
|
58
|
+
if (blockValidity.value)
|
|
56
59
|
return;
|
|
57
60
|
try {
|
|
58
|
-
//One
|
|
61
|
+
//One last try to get the txId status
|
|
59
62
|
const statusCheck = await this.getTxIdStatus(signature, finality);
|
|
60
|
-
if (statusCheck
|
|
63
|
+
if (statusCheck === "not_found")
|
|
61
64
|
reject(new Error("Transaction expired before confirmation, please try again!"));
|
|
65
|
+
status = statusCheck;
|
|
62
66
|
}
|
|
63
67
|
catch (e) {
|
|
64
68
|
this.logger.error("txConfirmationAndResendWatchdog(): re-check get tx id status error: ", e);
|
|
69
|
+
return;
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
if (status === "success") {
|
|
@@ -95,14 +100,22 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
|
|
|
95
100
|
const signature = bs58.encode(tx.signature);
|
|
96
101
|
let result;
|
|
97
102
|
try {
|
|
98
|
-
result = await
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
result = await new Promise((resolve, reject) => {
|
|
104
|
+
let subscriptionId;
|
|
105
|
+
if (abortSignal != null)
|
|
106
|
+
abortSignal.addEventListener("abort", () => {
|
|
107
|
+
if (subscriptionId != null)
|
|
108
|
+
this.connection.removeSignatureListener(subscriptionId).catch(e => {
|
|
109
|
+
this.logger.debug("txConfirmFromWebsocket(): remove WS signature confirm listener error: ", e);
|
|
110
|
+
});
|
|
111
|
+
subscriptionId = undefined;
|
|
112
|
+
reject(abortSignal.reason);
|
|
113
|
+
});
|
|
114
|
+
subscriptionId = this.connection.onSignature(signature, (data) => {
|
|
115
|
+
resolve(data);
|
|
116
|
+
subscriptionId = undefined;
|
|
105
117
|
}, finality);
|
|
118
|
+
});
|
|
106
119
|
this.logger.info("txConfirmFromWebsocket(): transaction confirmed from WS, signature: " + signature);
|
|
107
120
|
}
|
|
108
121
|
catch (err) {
|
|
@@ -122,7 +135,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
|
|
|
122
135
|
throw err;
|
|
123
136
|
}
|
|
124
137
|
}
|
|
125
|
-
if (result.
|
|
138
|
+
if (result.err != null)
|
|
126
139
|
throw new base_1.TransactionRevertedError("Transaction reverted!");
|
|
127
140
|
return signature;
|
|
128
141
|
}
|
|
@@ -137,10 +150,12 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
|
|
|
137
150
|
*/
|
|
138
151
|
async confirmTransaction(tx, abortSignal, finality) {
|
|
139
152
|
const abortController = new AbortController();
|
|
140
|
-
if (abortSignal != null)
|
|
153
|
+
if (abortSignal != null) {
|
|
154
|
+
abortSignal.throwIfAborted();
|
|
141
155
|
abortSignal.addEventListener("abort", () => {
|
|
142
|
-
abortController.abort();
|
|
156
|
+
abortController.abort(abortSignal.reason);
|
|
143
157
|
});
|
|
158
|
+
}
|
|
144
159
|
let txSignature;
|
|
145
160
|
try {
|
|
146
161
|
txSignature = await Promise.race([
|
|
@@ -254,8 +269,12 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
|
|
|
254
269
|
const signature = await this.sendSignedTransaction(solTx.tx, options, onBeforePublish);
|
|
255
270
|
const confirmPromise = this.confirmTransaction(solTx.tx, abortSignal, "confirmed");
|
|
256
271
|
//Don't await the last promise when !waitForConfirmation
|
|
257
|
-
if (i < txs.length - 1 || e + 50 < _txs.length || waitForConfirmation)
|
|
272
|
+
if (i < txs.length - 1 || e + 50 < _txs.length || waitForConfirmation) {
|
|
258
273
|
await confirmPromise;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
confirmPromise.catch(err => this.logger.error(`sendAndConfirm(): Error while awaiting confirmation of ${signature}: `, err));
|
|
277
|
+
}
|
|
259
278
|
signatures.push(signature);
|
|
260
279
|
}
|
|
261
280
|
}
|
|
@@ -279,25 +298,43 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
|
|
|
279
298
|
};
|
|
280
299
|
this.logger.debug("sendSignedAndConfirm(): sending transactions, count: " + signedTxs.length +
|
|
281
300
|
" waitForConfirmation: " + waitForConfirmation + " parallel: " + parallel);
|
|
301
|
+
const abortController = new AbortController();
|
|
302
|
+
if (abortSignal != null) {
|
|
303
|
+
abortSignal.throwIfAborted();
|
|
304
|
+
abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
|
|
305
|
+
}
|
|
282
306
|
const signatures = [];
|
|
283
307
|
const promises = [];
|
|
284
308
|
for (let i = 0; i < signedTxs.length; i++) {
|
|
285
309
|
const signedTx = signedTxs[i];
|
|
286
310
|
this.logger.debug("sendSignedAndConfirm(): sending transaction " + i + ", total count: " + signedTxs.length);
|
|
287
311
|
const signature = await this.sendSignedTransaction(signedTx, options, onBeforePublish);
|
|
288
|
-
|
|
312
|
+
if (abortSignal != null)
|
|
313
|
+
abortSignal.throwIfAborted();
|
|
314
|
+
const confirmPromise = this.confirmTransaction(signedTx, abortController.signal, "confirmed");
|
|
315
|
+
signatures.push(signature);
|
|
289
316
|
if (!parallel) {
|
|
290
317
|
//Don't await the last one when not wait for confirmations
|
|
291
|
-
if (i < signedTxs.length - 1 || waitForConfirmation)
|
|
318
|
+
if (i < signedTxs.length - 1 || waitForConfirmation) {
|
|
292
319
|
await confirmPromise;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
293
322
|
}
|
|
294
323
|
else {
|
|
295
|
-
|
|
324
|
+
if (waitForConfirmation) {
|
|
325
|
+
promises.push(confirmPromise.catch(err => {
|
|
326
|
+
this.logger.error(`sendSignedAndConfirm(): Error while awaiting confirmation of ${signature}: `, err);
|
|
327
|
+
abortController.abort(err);
|
|
328
|
+
}));
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
296
331
|
}
|
|
297
|
-
|
|
332
|
+
confirmPromise.catch(err => this.logger.error(`sendSignedAndConfirm(): Error while awaiting confirmation of ${signature}: `, err));
|
|
298
333
|
}
|
|
334
|
+
abortController.signal.throwIfAborted();
|
|
299
335
|
if (parallel && waitForConfirmation)
|
|
300
336
|
await Promise.all(promises);
|
|
337
|
+
abortController.signal.throwIfAborted();
|
|
301
338
|
this.logger.info("sendSignedAndConfirm(): sent transactions, count: " + signedTxs.length +
|
|
302
339
|
" waitForConfirmation: " + waitForConfirmation + " parallel: " + parallel);
|
|
303
340
|
return signatures;
|
|
@@ -359,7 +396,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
|
|
|
359
396
|
maxSupportedTransactionVersion: 0
|
|
360
397
|
});
|
|
361
398
|
if (txReceipt == null) {
|
|
362
|
-
const isValid = await this.connection.isBlockhashValid(parsedTx.recentBlockhash, { commitment: "processed" });
|
|
399
|
+
const { value: isValid } = await this.connection.isBlockhashValid(parsedTx.recentBlockhash, { commitment: "processed" });
|
|
363
400
|
if (!isValid)
|
|
364
401
|
return "not_found";
|
|
365
402
|
return "pending";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ComputeBudgetInstruction,
|
|
3
|
-
ComputeBudgetProgram, Finality, Keypair,
|
|
3
|
+
ComputeBudgetProgram, Finality, Keypair,
|
|
4
4
|
SendOptions, SignatureResult, Signer, Transaction,
|
|
5
5
|
TransactionExpiredBlockheightExceededError
|
|
6
6
|
} from "@solana/web3.js";
|
|
@@ -81,17 +81,23 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
81
81
|
);
|
|
82
82
|
this.logger.debug("txConfirmationAndResendWatchdog(): transaction re-sent: "+result);
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
let status = await this.getTxIdStatus(signature, finality).catch(
|
|
85
85
|
e => this.logger.error("txConfirmationAndResendWatchdog(): get tx id status error: ", e)
|
|
86
86
|
);
|
|
87
87
|
if(status==null || status==="not_found") {
|
|
88
|
-
|
|
88
|
+
const blockValidity = await this.connection.isBlockhashValid(tx.recentBlockhash!, {commitment: finality}).catch(
|
|
89
|
+
e => this.logger.error("txConfirmationAndResendWatchdog(): blockhash validity check error: ", e)
|
|
90
|
+
);
|
|
91
|
+
if(!blockValidity) return;
|
|
92
|
+
if(blockValidity.value) return;
|
|
89
93
|
try {
|
|
90
|
-
//One
|
|
94
|
+
//One last try to get the txId status
|
|
91
95
|
const statusCheck = await this.getTxIdStatus(signature, finality);
|
|
92
|
-
if(statusCheck
|
|
96
|
+
if(statusCheck === "not_found") reject(new Error("Transaction expired before confirmation, please try again!"));
|
|
97
|
+
status = statusCheck;
|
|
93
98
|
} catch (e) {
|
|
94
|
-
this.logger.error("txConfirmationAndResendWatchdog(): re-check get tx id status error: ", e)
|
|
99
|
+
this.logger.error("txConfirmationAndResendWatchdog(): re-check get tx id status error: ", e);
|
|
100
|
+
return;
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
if(status==="success") {
|
|
@@ -127,19 +133,24 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
127
133
|
if(tx.signature==null) throw new Error("Cannot wait for confirmation for tx without signature!");
|
|
128
134
|
const signature = bs58.encode(tx.signature);
|
|
129
135
|
|
|
130
|
-
let result:
|
|
136
|
+
let result: SignatureResult;
|
|
131
137
|
try {
|
|
132
|
-
result = await
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
result = await new Promise<SignatureResult>((resolve, reject) => {
|
|
139
|
+
let subscriptionId: number | undefined;
|
|
140
|
+
|
|
141
|
+
if(abortSignal!=null) abortSignal.addEventListener("abort", () => {
|
|
142
|
+
if(subscriptionId!=null) this.connection.removeSignatureListener(subscriptionId).catch(e => {
|
|
143
|
+
this.logger.debug("txConfirmFromWebsocket(): remove WS signature confirm listener error: ", e);
|
|
144
|
+
});
|
|
145
|
+
subscriptionId = undefined;
|
|
146
|
+
reject(abortSignal.reason);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
subscriptionId = this.connection.onSignature(signature, (data) => {
|
|
150
|
+
resolve(data);
|
|
151
|
+
subscriptionId = undefined;
|
|
152
|
+
}, finality);
|
|
153
|
+
});
|
|
143
154
|
this.logger.info("txConfirmFromWebsocket(): transaction confirmed from WS, signature: "+signature);
|
|
144
155
|
} catch (err: any) {
|
|
145
156
|
if(abortSignal!=null && abortSignal.aborted) throw err;
|
|
@@ -156,7 +167,7 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
156
167
|
throw err;
|
|
157
168
|
}
|
|
158
169
|
}
|
|
159
|
-
if(result.
|
|
170
|
+
if(result.err!=null) throw new TransactionRevertedError("Transaction reverted!");
|
|
160
171
|
return signature;
|
|
161
172
|
}
|
|
162
173
|
|
|
@@ -171,9 +182,12 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
171
182
|
*/
|
|
172
183
|
private async confirmTransaction(tx: Transaction, abortSignal?: AbortSignal, finality?: Finality) {
|
|
173
184
|
const abortController = new AbortController();
|
|
174
|
-
if(abortSignal!=null)
|
|
175
|
-
|
|
176
|
-
|
|
185
|
+
if(abortSignal!=null) {
|
|
186
|
+
abortSignal.throwIfAborted();
|
|
187
|
+
abortSignal.addEventListener("abort", () => {
|
|
188
|
+
abortController.abort(abortSignal.reason);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
177
191
|
|
|
178
192
|
let txSignature: string;
|
|
179
193
|
try {
|
|
@@ -294,7 +308,11 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
294
308
|
const signature = await this.sendSignedTransaction(solTx.tx, options, onBeforePublish);
|
|
295
309
|
const confirmPromise = this.confirmTransaction(solTx.tx, abortSignal, "confirmed");
|
|
296
310
|
//Don't await the last promise when !waitForConfirmation
|
|
297
|
-
if(i<txs.length-1 || e+50<_txs.length || waitForConfirmation)
|
|
311
|
+
if(i<txs.length-1 || e+50<_txs.length || waitForConfirmation) {
|
|
312
|
+
await confirmPromise;
|
|
313
|
+
} else {
|
|
314
|
+
confirmPromise.catch(err => this.logger.error(`sendAndConfirm(): Error while awaiting confirmation of ${signature}: `, err));
|
|
315
|
+
}
|
|
298
316
|
signatures.push(signature);
|
|
299
317
|
}
|
|
300
318
|
}
|
|
@@ -329,23 +347,42 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
329
347
|
this.logger.debug("sendSignedAndConfirm(): sending transactions, count: "+signedTxs.length+
|
|
330
348
|
" waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
|
|
331
349
|
|
|
350
|
+
const abortController = new AbortController();
|
|
351
|
+
if(abortSignal!=null) {
|
|
352
|
+
abortSignal.throwIfAborted();
|
|
353
|
+
abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
|
|
354
|
+
}
|
|
355
|
+
|
|
332
356
|
const signatures: string[] = [];
|
|
333
357
|
const promises: Promise<void>[] = [];
|
|
334
358
|
for(let i=0; i<signedTxs.length; i++) {
|
|
335
359
|
const signedTx = signedTxs[i];
|
|
336
360
|
this.logger.debug("sendSignedAndConfirm(): sending transaction "+i+", total count: "+signedTxs.length);
|
|
337
361
|
const signature = await this.sendSignedTransaction(signedTx, options, onBeforePublish);
|
|
338
|
-
|
|
362
|
+
if(abortSignal!=null) abortSignal.throwIfAborted();
|
|
363
|
+
const confirmPromise = this.confirmTransaction(signedTx, abortController.signal, "confirmed");
|
|
364
|
+
signatures.push(signature);
|
|
339
365
|
if(!parallel) {
|
|
340
366
|
//Don't await the last one when not wait for confirmations
|
|
341
|
-
if(i<signedTxs.length-1 || waitForConfirmation)
|
|
367
|
+
if(i<signedTxs.length-1 || waitForConfirmation) {
|
|
368
|
+
await confirmPromise;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
342
371
|
} else {
|
|
343
|
-
|
|
372
|
+
if(waitForConfirmation) {
|
|
373
|
+
promises.push(confirmPromise.catch(err => {
|
|
374
|
+
this.logger.error(`sendSignedAndConfirm(): Error while awaiting confirmation of ${signature}: `, err);
|
|
375
|
+
abortController.abort(err);
|
|
376
|
+
}));
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
344
379
|
}
|
|
345
|
-
|
|
380
|
+
confirmPromise.catch(err => this.logger.error(`sendSignedAndConfirm(): Error while awaiting confirmation of ${signature}: `, err));
|
|
346
381
|
}
|
|
347
382
|
|
|
383
|
+
abortController.signal.throwIfAborted();
|
|
348
384
|
if(parallel && waitForConfirmation) await Promise.all(promises);
|
|
385
|
+
abortController.signal.throwIfAborted();
|
|
349
386
|
|
|
350
387
|
this.logger.info("sendSignedAndConfirm(): sent transactions, count: "+signedTxs.length+
|
|
351
388
|
" waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
|
|
@@ -420,7 +457,7 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
420
457
|
maxSupportedTransactionVersion: 0
|
|
421
458
|
});
|
|
422
459
|
if(txReceipt==null) {
|
|
423
|
-
const isValid = await this.connection.isBlockhashValid(parsedTx.recentBlockhash!, {commitment: "processed"});
|
|
460
|
+
const {value: isValid} = await this.connection.isBlockhashValid(parsedTx.recentBlockhash!, {commitment: "processed"});
|
|
424
461
|
if(!isValid) return "not_found";
|
|
425
462
|
return "pending";
|
|
426
463
|
}
|