@solana/web3.js 1.41.8 → 1.42.0
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/lib/index.browser.cjs.js +182 -64
- package/lib/index.browser.cjs.js.map +1 -1
- package/lib/index.browser.esm.js +183 -65
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +182 -64
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +65 -22
- package/lib/index.esm.js +183 -65
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +182 -64
- package/lib/index.iife.js.map +1 -1
- package/lib/index.iife.min.js +2 -2
- package/lib/index.iife.min.js.map +1 -1
- package/package.json +2 -2
- package/src/connection.ts +157 -65
- package/src/transaction.ts +54 -6
- package/src/util/send-and-confirm-raw-transaction.ts +52 -7
- package/src/util/send-and-confirm-transaction.ts +19 -6
- package/src/util/tx-expiry-custom-errors.ts +35 -0
package/lib/index.browser.cjs.js
CHANGED
|
@@ -2376,9 +2376,17 @@ function assert (condition, message) {
|
|
|
2376
2376
|
}
|
|
2377
2377
|
}
|
|
2378
2378
|
|
|
2379
|
+
exports.TransactionStatus = void 0;
|
|
2379
2380
|
/**
|
|
2380
2381
|
* Default (empty) signature
|
|
2381
2382
|
*/
|
|
2383
|
+
|
|
2384
|
+
(function (TransactionStatus) {
|
|
2385
|
+
TransactionStatus[TransactionStatus["BLOCKHEIGHT_EXCEEDED"] = 0] = "BLOCKHEIGHT_EXCEEDED";
|
|
2386
|
+
TransactionStatus[TransactionStatus["PROCESSED"] = 1] = "PROCESSED";
|
|
2387
|
+
TransactionStatus[TransactionStatus["TIMED_OUT"] = 2] = "TIMED_OUT";
|
|
2388
|
+
})(exports.TransactionStatus || (exports.TransactionStatus = {}));
|
|
2389
|
+
|
|
2382
2390
|
const DEFAULT_SIGNATURE = buffer.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
|
|
2383
2391
|
/**
|
|
2384
2392
|
* Account metadata used to define instructions
|
|
@@ -2469,10 +2477,23 @@ class Transaction {
|
|
|
2469
2477
|
this.feePayer = void 0;
|
|
2470
2478
|
this.instructions = [];
|
|
2471
2479
|
this.recentBlockhash = void 0;
|
|
2480
|
+
this.lastValidBlockHeight = void 0;
|
|
2472
2481
|
this.nonceInfo = void 0;
|
|
2473
2482
|
this._message = void 0;
|
|
2474
2483
|
this._json = void 0;
|
|
2475
|
-
|
|
2484
|
+
|
|
2485
|
+
if (!opts) {
|
|
2486
|
+
return;
|
|
2487
|
+
} else if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
|
|
2488
|
+
const newOpts = opts;
|
|
2489
|
+
Object.assign(this, newOpts);
|
|
2490
|
+
this.recentBlockhash = newOpts.blockhash;
|
|
2491
|
+
this.lastValidBlockHeight = newOpts.lastValidBlockHeight;
|
|
2492
|
+
} else {
|
|
2493
|
+
const oldOpts = opts;
|
|
2494
|
+
Object.assign(this, oldOpts);
|
|
2495
|
+
this.recentBlockhash = oldOpts.recentBlockhash;
|
|
2496
|
+
}
|
|
2476
2497
|
}
|
|
2477
2498
|
/**
|
|
2478
2499
|
* @internal
|
|
@@ -3082,7 +3103,11 @@ async function sendAndConfirmTransaction(connection, transaction, signers, optio
|
|
|
3082
3103
|
maxRetries: options.maxRetries
|
|
3083
3104
|
};
|
|
3084
3105
|
const signature = await connection.sendTransaction(transaction, signers, sendOptions);
|
|
3085
|
-
const status = (await connection.confirmTransaction(
|
|
3106
|
+
const status = transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null ? (await connection.confirmTransaction({
|
|
3107
|
+
signature: signature,
|
|
3108
|
+
blockhash: transaction.recentBlockhash,
|
|
3109
|
+
lastValidBlockHeight: transaction.lastValidBlockHeight
|
|
3110
|
+
}, options && options.commitment)).value : (await connection.confirmTransaction(signature, options && options.commitment)).value;
|
|
3086
3111
|
|
|
3087
3112
|
if (status.err) {
|
|
3088
3113
|
throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
|
|
@@ -4994,16 +5019,28 @@ const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
|
|
|
4994
5019
|
|
|
4995
5020
|
const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
|
|
4996
5021
|
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5022
|
+
class TransactionExpiredBlockheightExceededError extends Error {
|
|
5023
|
+
constructor(signature) {
|
|
5024
|
+
super(`Signature ${signature} has expired: block height exceeded.`);
|
|
5025
|
+
this.signature = void 0;
|
|
5026
|
+
this.signature = signature;
|
|
5027
|
+
}
|
|
5028
|
+
|
|
5029
|
+
}
|
|
5030
|
+
Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
|
|
5031
|
+
value: 'TransactionExpiredBlockheightExceededError'
|
|
5032
|
+
});
|
|
5033
|
+
class TransactionExpiredTimeoutError extends Error {
|
|
5034
|
+
constructor(signature, timeoutSeconds) {
|
|
5035
|
+
super(`Transaction was not confirmed in ${timeoutSeconds.toFixed(2)} seconds. It is ` + 'unknown if it succeeded or failed. Check signature ' + `${signature} using the Solana Explorer or CLI tools.`);
|
|
5036
|
+
this.signature = void 0;
|
|
5037
|
+
this.signature = signature;
|
|
5038
|
+
}
|
|
5039
|
+
|
|
5006
5040
|
}
|
|
5041
|
+
Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
|
|
5042
|
+
value: 'TransactionExpiredTimeoutError'
|
|
5043
|
+
});
|
|
5007
5044
|
|
|
5008
5045
|
function makeWebsocketUrl(endpoint) {
|
|
5009
5046
|
let url = new URL(endpoint);
|
|
@@ -5992,7 +6029,7 @@ class Connection {
|
|
|
5992
6029
|
this._disableBlockhashCaching = false;
|
|
5993
6030
|
this._pollingBlockhash = false;
|
|
5994
6031
|
this._blockhashInfo = {
|
|
5995
|
-
|
|
6032
|
+
latestBlockhash: null,
|
|
5996
6033
|
lastFetch: 0,
|
|
5997
6034
|
transactionSignatures: [],
|
|
5998
6035
|
simulatedSignatures: []
|
|
@@ -6473,67 +6510,124 @@ class Connection {
|
|
|
6473
6510
|
|
|
6474
6511
|
return res.result;
|
|
6475
6512
|
}
|
|
6476
|
-
/**
|
|
6477
|
-
* Confirm the transaction identified by the specified signature.
|
|
6478
|
-
*/
|
|
6479
6513
|
|
|
6514
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
6515
|
+
async confirmTransaction(strategy, commitment) {
|
|
6516
|
+
let rawSignature;
|
|
6517
|
+
|
|
6518
|
+
if (typeof strategy == 'string') {
|
|
6519
|
+
rawSignature = strategy;
|
|
6520
|
+
} else {
|
|
6521
|
+
const config = strategy;
|
|
6522
|
+
rawSignature = config.signature;
|
|
6523
|
+
}
|
|
6480
6524
|
|
|
6481
|
-
async confirmTransaction(signature, commitment) {
|
|
6482
6525
|
let decodedSignature;
|
|
6483
6526
|
|
|
6484
6527
|
try {
|
|
6485
|
-
decodedSignature = bs58__default["default"].decode(
|
|
6528
|
+
decodedSignature = bs58__default["default"].decode(rawSignature);
|
|
6486
6529
|
} catch (err) {
|
|
6487
|
-
throw new Error('signature must be base58 encoded: ' +
|
|
6530
|
+
throw new Error('signature must be base58 encoded: ' + rawSignature);
|
|
6488
6531
|
}
|
|
6489
6532
|
|
|
6490
6533
|
assert(decodedSignature.length === 64, 'signature has invalid length');
|
|
6491
|
-
const start = Date.now();
|
|
6492
6534
|
const subscriptionCommitment = commitment || this.commitment;
|
|
6535
|
+
let timeoutId;
|
|
6493
6536
|
let subscriptionId;
|
|
6494
|
-
let
|
|
6495
|
-
const
|
|
6537
|
+
let done = false;
|
|
6538
|
+
const confirmationPromise = new Promise((resolve, reject) => {
|
|
6496
6539
|
try {
|
|
6497
|
-
subscriptionId = this.onSignature(
|
|
6540
|
+
subscriptionId = this.onSignature(rawSignature, (result, context) => {
|
|
6498
6541
|
subscriptionId = undefined;
|
|
6499
|
-
response = {
|
|
6542
|
+
const response = {
|
|
6500
6543
|
context,
|
|
6501
6544
|
value: result
|
|
6502
6545
|
};
|
|
6503
|
-
|
|
6546
|
+
done = true;
|
|
6547
|
+
resolve({
|
|
6548
|
+
__type: exports.TransactionStatus.PROCESSED,
|
|
6549
|
+
response
|
|
6550
|
+
});
|
|
6504
6551
|
}, subscriptionCommitment);
|
|
6505
6552
|
} catch (err) {
|
|
6506
6553
|
reject(err);
|
|
6507
6554
|
}
|
|
6508
6555
|
});
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6556
|
+
|
|
6557
|
+
const checkBlockHeight = async () => {
|
|
6558
|
+
try {
|
|
6559
|
+
const blockHeight = await this.getBlockHeight(commitment);
|
|
6560
|
+
return blockHeight;
|
|
6561
|
+
} catch (_e) {
|
|
6562
|
+
return -1;
|
|
6563
|
+
}
|
|
6564
|
+
};
|
|
6565
|
+
|
|
6566
|
+
const expiryPromise = new Promise(resolve => {
|
|
6567
|
+
if (typeof strategy === 'string') {
|
|
6568
|
+
let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
|
|
6569
|
+
|
|
6570
|
+
switch (subscriptionCommitment) {
|
|
6571
|
+
case 'processed':
|
|
6572
|
+
case 'recent':
|
|
6573
|
+
case 'single':
|
|
6574
|
+
case 'confirmed':
|
|
6575
|
+
case 'singleGossip':
|
|
6576
|
+
{
|
|
6577
|
+
timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
|
|
6578
|
+
break;
|
|
6579
|
+
}
|
|
6520
6580
|
}
|
|
6521
|
-
|
|
6581
|
+
|
|
6582
|
+
timeoutId = setTimeout(() => resolve({
|
|
6583
|
+
__type: exports.TransactionStatus.TIMED_OUT,
|
|
6584
|
+
timeoutMs
|
|
6585
|
+
}), timeoutMs);
|
|
6586
|
+
} else {
|
|
6587
|
+
let config = strategy;
|
|
6588
|
+
|
|
6589
|
+
(async () => {
|
|
6590
|
+
let currentBlockHeight = await checkBlockHeight();
|
|
6591
|
+
if (done) return;
|
|
6592
|
+
|
|
6593
|
+
while (currentBlockHeight <= config.lastValidBlockHeight) {
|
|
6594
|
+
await sleep(1000);
|
|
6595
|
+
if (done) return;
|
|
6596
|
+
currentBlockHeight = await checkBlockHeight();
|
|
6597
|
+
if (done) return;
|
|
6598
|
+
}
|
|
6599
|
+
|
|
6600
|
+
resolve({
|
|
6601
|
+
__type: exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED
|
|
6602
|
+
});
|
|
6603
|
+
})();
|
|
6604
|
+
}
|
|
6605
|
+
});
|
|
6606
|
+
let result;
|
|
6522
6607
|
|
|
6523
6608
|
try {
|
|
6524
|
-
await
|
|
6609
|
+
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
|
|
6610
|
+
|
|
6611
|
+
switch (outcome.__type) {
|
|
6612
|
+
case exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED:
|
|
6613
|
+
throw new TransactionExpiredBlockheightExceededError(rawSignature);
|
|
6614
|
+
|
|
6615
|
+
case exports.TransactionStatus.PROCESSED:
|
|
6616
|
+
result = outcome.response;
|
|
6617
|
+
break;
|
|
6618
|
+
|
|
6619
|
+
case exports.TransactionStatus.TIMED_OUT:
|
|
6620
|
+
throw new TransactionExpiredTimeoutError(rawSignature, outcome.timeoutMs / 1000);
|
|
6621
|
+
}
|
|
6525
6622
|
} finally {
|
|
6623
|
+
clearTimeout(timeoutId);
|
|
6624
|
+
|
|
6526
6625
|
if (subscriptionId) {
|
|
6527
6626
|
this.removeSignatureListener(subscriptionId);
|
|
6528
6627
|
}
|
|
6529
6628
|
}
|
|
6530
6629
|
|
|
6531
|
-
|
|
6532
|
-
const duration = (Date.now() - start) / 1000;
|
|
6533
|
-
throw new Error(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`);
|
|
6534
|
-
}
|
|
6535
|
-
|
|
6536
|
-
return response;
|
|
6630
|
+
return result;
|
|
6537
6631
|
}
|
|
6538
6632
|
/**
|
|
6539
6633
|
* Return the list of nodes that are currently participating in the cluster
|
|
@@ -6898,7 +6992,7 @@ class Connection {
|
|
|
6898
6992
|
}
|
|
6899
6993
|
/**
|
|
6900
6994
|
* Fetch the latest blockhash from the cluster
|
|
6901
|
-
* @return {Promise<
|
|
6995
|
+
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
|
6902
6996
|
*/
|
|
6903
6997
|
|
|
6904
6998
|
|
|
@@ -6912,7 +7006,7 @@ class Connection {
|
|
|
6912
7006
|
}
|
|
6913
7007
|
/**
|
|
6914
7008
|
* Fetch the latest blockhash from the cluster
|
|
6915
|
-
* @return {Promise<
|
|
7009
|
+
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
|
6916
7010
|
*/
|
|
6917
7011
|
|
|
6918
7012
|
|
|
@@ -7495,7 +7589,7 @@ class Connection {
|
|
|
7495
7589
|
*/
|
|
7496
7590
|
|
|
7497
7591
|
|
|
7498
|
-
async
|
|
7592
|
+
async _blockhashWithExpiryBlockHeight(disableCache) {
|
|
7499
7593
|
if (!disableCache) {
|
|
7500
7594
|
// Wait for polling to finish
|
|
7501
7595
|
while (this._pollingBlockhash) {
|
|
@@ -7506,8 +7600,8 @@ class Connection {
|
|
|
7506
7600
|
|
|
7507
7601
|
const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
|
|
7508
7602
|
|
|
7509
|
-
if (this._blockhashInfo.
|
|
7510
|
-
return this._blockhashInfo.
|
|
7603
|
+
if (this._blockhashInfo.latestBlockhash !== null && !expired) {
|
|
7604
|
+
return this._blockhashInfo.latestBlockhash;
|
|
7511
7605
|
}
|
|
7512
7606
|
}
|
|
7513
7607
|
|
|
@@ -7523,20 +7617,20 @@ class Connection {
|
|
|
7523
7617
|
|
|
7524
7618
|
try {
|
|
7525
7619
|
const startTime = Date.now();
|
|
7620
|
+
const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
|
|
7621
|
+
const cachedBlockhash = cachedLatestBlockhash ? cachedLatestBlockhash.blockhash : null;
|
|
7526
7622
|
|
|
7527
7623
|
for (let i = 0; i < 50; i++) {
|
|
7528
|
-
const
|
|
7529
|
-
blockhash
|
|
7530
|
-
} = await this.getRecentBlockhash('finalized');
|
|
7624
|
+
const latestBlockhash = await this.getLatestBlockhash('finalized');
|
|
7531
7625
|
|
|
7532
|
-
if (
|
|
7626
|
+
if (cachedBlockhash !== latestBlockhash.blockhash) {
|
|
7533
7627
|
this._blockhashInfo = {
|
|
7534
|
-
|
|
7628
|
+
latestBlockhash,
|
|
7535
7629
|
lastFetch: Date.now(),
|
|
7536
7630
|
transactionSignatures: [],
|
|
7537
7631
|
simulatedSignatures: []
|
|
7538
7632
|
};
|
|
7539
|
-
return
|
|
7633
|
+
return latestBlockhash;
|
|
7540
7634
|
} // Sleep for approximately half a slot
|
|
7541
7635
|
|
|
7542
7636
|
|
|
@@ -7558,13 +7652,11 @@ class Connection {
|
|
|
7558
7652
|
|
|
7559
7653
|
if (transactionOrMessage instanceof Transaction) {
|
|
7560
7654
|
let originalTx = transactionOrMessage;
|
|
7561
|
-
transaction = new Transaction(
|
|
7562
|
-
|
|
7563
|
-
nonceInfo: originalTx.nonceInfo,
|
|
7564
|
-
feePayer: originalTx.feePayer,
|
|
7565
|
-
signatures: [...originalTx.signatures]
|
|
7566
|
-
});
|
|
7655
|
+
transaction = new Transaction();
|
|
7656
|
+
transaction.feePayer = originalTx.feePayer;
|
|
7567
7657
|
transaction.instructions = transactionOrMessage.instructions;
|
|
7658
|
+
transaction.nonceInfo = originalTx.nonceInfo;
|
|
7659
|
+
transaction.signatures = originalTx.signatures;
|
|
7568
7660
|
} else {
|
|
7569
7661
|
transaction = Transaction.populate(transactionOrMessage); // HACK: this function relies on mutating the populated transaction
|
|
7570
7662
|
|
|
@@ -7577,7 +7669,9 @@ class Connection {
|
|
|
7577
7669
|
let disableCache = this._disableBlockhashCaching;
|
|
7578
7670
|
|
|
7579
7671
|
for (;;) {
|
|
7580
|
-
|
|
7672
|
+
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
|
|
7673
|
+
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
7674
|
+
transaction.recentBlockhash = latestBlockhash.blockhash;
|
|
7581
7675
|
if (!signers) break;
|
|
7582
7676
|
transaction.sign(...signers);
|
|
7583
7677
|
|
|
@@ -7661,7 +7755,9 @@ class Connection {
|
|
|
7661
7755
|
let disableCache = this._disableBlockhashCaching;
|
|
7662
7756
|
|
|
7663
7757
|
for (;;) {
|
|
7664
|
-
|
|
7758
|
+
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
|
|
7759
|
+
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
7760
|
+
transaction.recentBlockhash = latestBlockhash.blockhash;
|
|
7665
7761
|
transaction.sign(...signers);
|
|
7666
7762
|
|
|
7667
7763
|
if (!transaction.signature) {
|
|
@@ -7761,6 +7857,7 @@ class Connection {
|
|
|
7761
7857
|
|
|
7762
7858
|
|
|
7763
7859
|
_wsOnError(err) {
|
|
7860
|
+
this._rpcWebSocketConnected = false;
|
|
7764
7861
|
console.error('ws error:', err.message);
|
|
7765
7862
|
}
|
|
7766
7863
|
/**
|
|
@@ -7769,6 +7866,7 @@ class Connection {
|
|
|
7769
7866
|
|
|
7770
7867
|
|
|
7771
7868
|
_wsOnClose(code) {
|
|
7869
|
+
this._rpcWebSocketConnected = false;
|
|
7772
7870
|
this._rpcWebSocketGeneration++;
|
|
7773
7871
|
|
|
7774
7872
|
if (this._rpcWebSocketHeartbeat) {
|
|
@@ -10100,16 +10198,36 @@ VoteProgram.space = 3731;
|
|
|
10100
10198
|
*
|
|
10101
10199
|
* @param {Connection} connection
|
|
10102
10200
|
* @param {Buffer} rawTransaction
|
|
10201
|
+
* @param {BlockheightBasedTransactionConfimationStrategy} confirmationStrategy
|
|
10103
10202
|
* @param {ConfirmOptions} [options]
|
|
10104
10203
|
* @returns {Promise<TransactionSignature>}
|
|
10105
10204
|
*/
|
|
10106
|
-
|
|
10205
|
+
|
|
10206
|
+
/**
|
|
10207
|
+
* @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
|
|
10208
|
+
* is no longer supported and will be removed in a future version.
|
|
10209
|
+
*/
|
|
10210
|
+
// eslint-disable-next-line no-redeclare
|
|
10211
|
+
// eslint-disable-next-line no-redeclare
|
|
10212
|
+
async function sendAndConfirmRawTransaction(connection, rawTransaction, confirmationStrategyOrConfirmOptions, maybeConfirmOptions) {
|
|
10213
|
+
let confirmationStrategy;
|
|
10214
|
+
let options;
|
|
10215
|
+
|
|
10216
|
+
if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'lastValidBlockHeight')) {
|
|
10217
|
+
confirmationStrategy = confirmationStrategyOrConfirmOptions;
|
|
10218
|
+
options = maybeConfirmOptions;
|
|
10219
|
+
} else {
|
|
10220
|
+
options = confirmationStrategyOrConfirmOptions;
|
|
10221
|
+
}
|
|
10222
|
+
|
|
10107
10223
|
const sendOptions = options && {
|
|
10108
10224
|
skipPreflight: options.skipPreflight,
|
|
10109
10225
|
preflightCommitment: options.preflightCommitment || options.commitment
|
|
10110
10226
|
};
|
|
10111
10227
|
const signature = await connection.sendRawTransaction(rawTransaction, sendOptions);
|
|
10112
|
-
const
|
|
10228
|
+
const commitment = options && options.commitment;
|
|
10229
|
+
const confirmationPromise = confirmationStrategy ? connection.confirmTransaction(confirmationStrategy, commitment) : connection.confirmTransaction(signature, commitment);
|
|
10230
|
+
const status = (await confirmationPromise).value;
|
|
10113
10231
|
|
|
10114
10232
|
if (status.err) {
|
|
10115
10233
|
throw new Error(`Raw transaction ${signature} failed (${JSON.stringify(status)})`);
|