@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.cjs.js
CHANGED
|
@@ -2388,9 +2388,17 @@ function assert (condition, message) {
|
|
|
2388
2388
|
}
|
|
2389
2389
|
}
|
|
2390
2390
|
|
|
2391
|
+
exports.TransactionStatus = void 0;
|
|
2391
2392
|
/**
|
|
2392
2393
|
* Default (empty) signature
|
|
2393
2394
|
*/
|
|
2395
|
+
|
|
2396
|
+
(function (TransactionStatus) {
|
|
2397
|
+
TransactionStatus[TransactionStatus["BLOCKHEIGHT_EXCEEDED"] = 0] = "BLOCKHEIGHT_EXCEEDED";
|
|
2398
|
+
TransactionStatus[TransactionStatus["PROCESSED"] = 1] = "PROCESSED";
|
|
2399
|
+
TransactionStatus[TransactionStatus["TIMED_OUT"] = 2] = "TIMED_OUT";
|
|
2400
|
+
})(exports.TransactionStatus || (exports.TransactionStatus = {}));
|
|
2401
|
+
|
|
2394
2402
|
const DEFAULT_SIGNATURE = buffer.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
|
|
2395
2403
|
/**
|
|
2396
2404
|
* Account metadata used to define instructions
|
|
@@ -2481,10 +2489,23 @@ class Transaction {
|
|
|
2481
2489
|
this.feePayer = void 0;
|
|
2482
2490
|
this.instructions = [];
|
|
2483
2491
|
this.recentBlockhash = void 0;
|
|
2492
|
+
this.lastValidBlockHeight = void 0;
|
|
2484
2493
|
this.nonceInfo = void 0;
|
|
2485
2494
|
this._message = void 0;
|
|
2486
2495
|
this._json = void 0;
|
|
2487
|
-
|
|
2496
|
+
|
|
2497
|
+
if (!opts) {
|
|
2498
|
+
return;
|
|
2499
|
+
} else if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
|
|
2500
|
+
const newOpts = opts;
|
|
2501
|
+
Object.assign(this, newOpts);
|
|
2502
|
+
this.recentBlockhash = newOpts.blockhash;
|
|
2503
|
+
this.lastValidBlockHeight = newOpts.lastValidBlockHeight;
|
|
2504
|
+
} else {
|
|
2505
|
+
const oldOpts = opts;
|
|
2506
|
+
Object.assign(this, oldOpts);
|
|
2507
|
+
this.recentBlockhash = oldOpts.recentBlockhash;
|
|
2508
|
+
}
|
|
2488
2509
|
}
|
|
2489
2510
|
/**
|
|
2490
2511
|
* @internal
|
|
@@ -3094,7 +3115,11 @@ async function sendAndConfirmTransaction(connection, transaction, signers, optio
|
|
|
3094
3115
|
maxRetries: options.maxRetries
|
|
3095
3116
|
};
|
|
3096
3117
|
const signature = await connection.sendTransaction(transaction, signers, sendOptions);
|
|
3097
|
-
const status = (await connection.confirmTransaction(
|
|
3118
|
+
const status = transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null ? (await connection.confirmTransaction({
|
|
3119
|
+
signature: signature,
|
|
3120
|
+
blockhash: transaction.recentBlockhash,
|
|
3121
|
+
lastValidBlockHeight: transaction.lastValidBlockHeight
|
|
3122
|
+
}, options && options.commitment)).value : (await connection.confirmTransaction(signature, options && options.commitment)).value;
|
|
3098
3123
|
|
|
3099
3124
|
if (status.err) {
|
|
3100
3125
|
throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
|
|
@@ -4494,16 +4519,28 @@ const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
|
|
|
4494
4519
|
|
|
4495
4520
|
const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
|
|
4496
4521
|
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4522
|
+
class TransactionExpiredBlockheightExceededError extends Error {
|
|
4523
|
+
constructor(signature) {
|
|
4524
|
+
super(`Signature ${signature} has expired: block height exceeded.`);
|
|
4525
|
+
this.signature = void 0;
|
|
4526
|
+
this.signature = signature;
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
}
|
|
4530
|
+
Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
|
|
4531
|
+
value: 'TransactionExpiredBlockheightExceededError'
|
|
4532
|
+
});
|
|
4533
|
+
class TransactionExpiredTimeoutError extends Error {
|
|
4534
|
+
constructor(signature, timeoutSeconds) {
|
|
4535
|
+
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.`);
|
|
4536
|
+
this.signature = void 0;
|
|
4537
|
+
this.signature = signature;
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4506
4540
|
}
|
|
4541
|
+
Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
|
|
4542
|
+
value: 'TransactionExpiredTimeoutError'
|
|
4543
|
+
});
|
|
4507
4544
|
|
|
4508
4545
|
function makeWebsocketUrl(endpoint) {
|
|
4509
4546
|
let url = new URL(endpoint);
|
|
@@ -5498,7 +5535,7 @@ class Connection {
|
|
|
5498
5535
|
this._disableBlockhashCaching = false;
|
|
5499
5536
|
this._pollingBlockhash = false;
|
|
5500
5537
|
this._blockhashInfo = {
|
|
5501
|
-
|
|
5538
|
+
latestBlockhash: null,
|
|
5502
5539
|
lastFetch: 0,
|
|
5503
5540
|
transactionSignatures: [],
|
|
5504
5541
|
simulatedSignatures: []
|
|
@@ -5979,67 +6016,124 @@ class Connection {
|
|
|
5979
6016
|
|
|
5980
6017
|
return res.result;
|
|
5981
6018
|
}
|
|
5982
|
-
/**
|
|
5983
|
-
* Confirm the transaction identified by the specified signature.
|
|
5984
|
-
*/
|
|
5985
6019
|
|
|
6020
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
6021
|
+
async confirmTransaction(strategy, commitment) {
|
|
6022
|
+
let rawSignature;
|
|
6023
|
+
|
|
6024
|
+
if (typeof strategy == 'string') {
|
|
6025
|
+
rawSignature = strategy;
|
|
6026
|
+
} else {
|
|
6027
|
+
const config = strategy;
|
|
6028
|
+
rawSignature = config.signature;
|
|
6029
|
+
}
|
|
5986
6030
|
|
|
5987
|
-
async confirmTransaction(signature, commitment) {
|
|
5988
6031
|
let decodedSignature;
|
|
5989
6032
|
|
|
5990
6033
|
try {
|
|
5991
|
-
decodedSignature = bs58__default["default"].decode(
|
|
6034
|
+
decodedSignature = bs58__default["default"].decode(rawSignature);
|
|
5992
6035
|
} catch (err) {
|
|
5993
|
-
throw new Error('signature must be base58 encoded: ' +
|
|
6036
|
+
throw new Error('signature must be base58 encoded: ' + rawSignature);
|
|
5994
6037
|
}
|
|
5995
6038
|
|
|
5996
6039
|
assert(decodedSignature.length === 64, 'signature has invalid length');
|
|
5997
|
-
const start = Date.now();
|
|
5998
6040
|
const subscriptionCommitment = commitment || this.commitment;
|
|
6041
|
+
let timeoutId;
|
|
5999
6042
|
let subscriptionId;
|
|
6000
|
-
let
|
|
6001
|
-
const
|
|
6043
|
+
let done = false;
|
|
6044
|
+
const confirmationPromise = new Promise((resolve, reject) => {
|
|
6002
6045
|
try {
|
|
6003
|
-
subscriptionId = this.onSignature(
|
|
6046
|
+
subscriptionId = this.onSignature(rawSignature, (result, context) => {
|
|
6004
6047
|
subscriptionId = undefined;
|
|
6005
|
-
response = {
|
|
6048
|
+
const response = {
|
|
6006
6049
|
context,
|
|
6007
6050
|
value: result
|
|
6008
6051
|
};
|
|
6009
|
-
|
|
6052
|
+
done = true;
|
|
6053
|
+
resolve({
|
|
6054
|
+
__type: exports.TransactionStatus.PROCESSED,
|
|
6055
|
+
response
|
|
6056
|
+
});
|
|
6010
6057
|
}, subscriptionCommitment);
|
|
6011
6058
|
} catch (err) {
|
|
6012
6059
|
reject(err);
|
|
6013
6060
|
}
|
|
6014
6061
|
});
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6062
|
+
|
|
6063
|
+
const checkBlockHeight = async () => {
|
|
6064
|
+
try {
|
|
6065
|
+
const blockHeight = await this.getBlockHeight(commitment);
|
|
6066
|
+
return blockHeight;
|
|
6067
|
+
} catch (_e) {
|
|
6068
|
+
return -1;
|
|
6069
|
+
}
|
|
6070
|
+
};
|
|
6071
|
+
|
|
6072
|
+
const expiryPromise = new Promise(resolve => {
|
|
6073
|
+
if (typeof strategy === 'string') {
|
|
6074
|
+
let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
|
|
6075
|
+
|
|
6076
|
+
switch (subscriptionCommitment) {
|
|
6077
|
+
case 'processed':
|
|
6078
|
+
case 'recent':
|
|
6079
|
+
case 'single':
|
|
6080
|
+
case 'confirmed':
|
|
6081
|
+
case 'singleGossip':
|
|
6082
|
+
{
|
|
6083
|
+
timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
|
|
6084
|
+
break;
|
|
6085
|
+
}
|
|
6026
6086
|
}
|
|
6027
|
-
|
|
6087
|
+
|
|
6088
|
+
timeoutId = setTimeout(() => resolve({
|
|
6089
|
+
__type: exports.TransactionStatus.TIMED_OUT,
|
|
6090
|
+
timeoutMs
|
|
6091
|
+
}), timeoutMs);
|
|
6092
|
+
} else {
|
|
6093
|
+
let config = strategy;
|
|
6094
|
+
|
|
6095
|
+
(async () => {
|
|
6096
|
+
let currentBlockHeight = await checkBlockHeight();
|
|
6097
|
+
if (done) return;
|
|
6098
|
+
|
|
6099
|
+
while (currentBlockHeight <= config.lastValidBlockHeight) {
|
|
6100
|
+
await sleep(1000);
|
|
6101
|
+
if (done) return;
|
|
6102
|
+
currentBlockHeight = await checkBlockHeight();
|
|
6103
|
+
if (done) return;
|
|
6104
|
+
}
|
|
6105
|
+
|
|
6106
|
+
resolve({
|
|
6107
|
+
__type: exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED
|
|
6108
|
+
});
|
|
6109
|
+
})();
|
|
6110
|
+
}
|
|
6111
|
+
});
|
|
6112
|
+
let result;
|
|
6028
6113
|
|
|
6029
6114
|
try {
|
|
6030
|
-
await
|
|
6115
|
+
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
|
|
6116
|
+
|
|
6117
|
+
switch (outcome.__type) {
|
|
6118
|
+
case exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED:
|
|
6119
|
+
throw new TransactionExpiredBlockheightExceededError(rawSignature);
|
|
6120
|
+
|
|
6121
|
+
case exports.TransactionStatus.PROCESSED:
|
|
6122
|
+
result = outcome.response;
|
|
6123
|
+
break;
|
|
6124
|
+
|
|
6125
|
+
case exports.TransactionStatus.TIMED_OUT:
|
|
6126
|
+
throw new TransactionExpiredTimeoutError(rawSignature, outcome.timeoutMs / 1000);
|
|
6127
|
+
}
|
|
6031
6128
|
} finally {
|
|
6129
|
+
clearTimeout(timeoutId);
|
|
6130
|
+
|
|
6032
6131
|
if (subscriptionId) {
|
|
6033
6132
|
this.removeSignatureListener(subscriptionId);
|
|
6034
6133
|
}
|
|
6035
6134
|
}
|
|
6036
6135
|
|
|
6037
|
-
|
|
6038
|
-
const duration = (Date.now() - start) / 1000;
|
|
6039
|
-
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.`);
|
|
6040
|
-
}
|
|
6041
|
-
|
|
6042
|
-
return response;
|
|
6136
|
+
return result;
|
|
6043
6137
|
}
|
|
6044
6138
|
/**
|
|
6045
6139
|
* Return the list of nodes that are currently participating in the cluster
|
|
@@ -6404,7 +6498,7 @@ class Connection {
|
|
|
6404
6498
|
}
|
|
6405
6499
|
/**
|
|
6406
6500
|
* Fetch the latest blockhash from the cluster
|
|
6407
|
-
* @return {Promise<
|
|
6501
|
+
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
|
6408
6502
|
*/
|
|
6409
6503
|
|
|
6410
6504
|
|
|
@@ -6418,7 +6512,7 @@ class Connection {
|
|
|
6418
6512
|
}
|
|
6419
6513
|
/**
|
|
6420
6514
|
* Fetch the latest blockhash from the cluster
|
|
6421
|
-
* @return {Promise<
|
|
6515
|
+
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
|
6422
6516
|
*/
|
|
6423
6517
|
|
|
6424
6518
|
|
|
@@ -7001,7 +7095,7 @@ class Connection {
|
|
|
7001
7095
|
*/
|
|
7002
7096
|
|
|
7003
7097
|
|
|
7004
|
-
async
|
|
7098
|
+
async _blockhashWithExpiryBlockHeight(disableCache) {
|
|
7005
7099
|
if (!disableCache) {
|
|
7006
7100
|
// Wait for polling to finish
|
|
7007
7101
|
while (this._pollingBlockhash) {
|
|
@@ -7012,8 +7106,8 @@ class Connection {
|
|
|
7012
7106
|
|
|
7013
7107
|
const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
|
|
7014
7108
|
|
|
7015
|
-
if (this._blockhashInfo.
|
|
7016
|
-
return this._blockhashInfo.
|
|
7109
|
+
if (this._blockhashInfo.latestBlockhash !== null && !expired) {
|
|
7110
|
+
return this._blockhashInfo.latestBlockhash;
|
|
7017
7111
|
}
|
|
7018
7112
|
}
|
|
7019
7113
|
|
|
@@ -7029,20 +7123,20 @@ class Connection {
|
|
|
7029
7123
|
|
|
7030
7124
|
try {
|
|
7031
7125
|
const startTime = Date.now();
|
|
7126
|
+
const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
|
|
7127
|
+
const cachedBlockhash = cachedLatestBlockhash ? cachedLatestBlockhash.blockhash : null;
|
|
7032
7128
|
|
|
7033
7129
|
for (let i = 0; i < 50; i++) {
|
|
7034
|
-
const
|
|
7035
|
-
blockhash
|
|
7036
|
-
} = await this.getRecentBlockhash('finalized');
|
|
7130
|
+
const latestBlockhash = await this.getLatestBlockhash('finalized');
|
|
7037
7131
|
|
|
7038
|
-
if (
|
|
7132
|
+
if (cachedBlockhash !== latestBlockhash.blockhash) {
|
|
7039
7133
|
this._blockhashInfo = {
|
|
7040
|
-
|
|
7134
|
+
latestBlockhash,
|
|
7041
7135
|
lastFetch: Date.now(),
|
|
7042
7136
|
transactionSignatures: [],
|
|
7043
7137
|
simulatedSignatures: []
|
|
7044
7138
|
};
|
|
7045
|
-
return
|
|
7139
|
+
return latestBlockhash;
|
|
7046
7140
|
} // Sleep for approximately half a slot
|
|
7047
7141
|
|
|
7048
7142
|
|
|
@@ -7064,13 +7158,11 @@ class Connection {
|
|
|
7064
7158
|
|
|
7065
7159
|
if (transactionOrMessage instanceof Transaction) {
|
|
7066
7160
|
let originalTx = transactionOrMessage;
|
|
7067
|
-
transaction = new Transaction(
|
|
7068
|
-
|
|
7069
|
-
nonceInfo: originalTx.nonceInfo,
|
|
7070
|
-
feePayer: originalTx.feePayer,
|
|
7071
|
-
signatures: [...originalTx.signatures]
|
|
7072
|
-
});
|
|
7161
|
+
transaction = new Transaction();
|
|
7162
|
+
transaction.feePayer = originalTx.feePayer;
|
|
7073
7163
|
transaction.instructions = transactionOrMessage.instructions;
|
|
7164
|
+
transaction.nonceInfo = originalTx.nonceInfo;
|
|
7165
|
+
transaction.signatures = originalTx.signatures;
|
|
7074
7166
|
} else {
|
|
7075
7167
|
transaction = Transaction.populate(transactionOrMessage); // HACK: this function relies on mutating the populated transaction
|
|
7076
7168
|
|
|
@@ -7083,7 +7175,9 @@ class Connection {
|
|
|
7083
7175
|
let disableCache = this._disableBlockhashCaching;
|
|
7084
7176
|
|
|
7085
7177
|
for (;;) {
|
|
7086
|
-
|
|
7178
|
+
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
|
|
7179
|
+
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
7180
|
+
transaction.recentBlockhash = latestBlockhash.blockhash;
|
|
7087
7181
|
if (!signers) break;
|
|
7088
7182
|
transaction.sign(...signers);
|
|
7089
7183
|
|
|
@@ -7167,7 +7261,9 @@ class Connection {
|
|
|
7167
7261
|
let disableCache = this._disableBlockhashCaching;
|
|
7168
7262
|
|
|
7169
7263
|
for (;;) {
|
|
7170
|
-
|
|
7264
|
+
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
|
|
7265
|
+
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
7266
|
+
transaction.recentBlockhash = latestBlockhash.blockhash;
|
|
7171
7267
|
transaction.sign(...signers);
|
|
7172
7268
|
|
|
7173
7269
|
if (!transaction.signature) {
|
|
@@ -7267,6 +7363,7 @@ class Connection {
|
|
|
7267
7363
|
|
|
7268
7364
|
|
|
7269
7365
|
_wsOnError(err) {
|
|
7366
|
+
this._rpcWebSocketConnected = false;
|
|
7270
7367
|
console.error('ws error:', err.message);
|
|
7271
7368
|
}
|
|
7272
7369
|
/**
|
|
@@ -7275,6 +7372,7 @@ class Connection {
|
|
|
7275
7372
|
|
|
7276
7373
|
|
|
7277
7374
|
_wsOnClose(code) {
|
|
7375
|
+
this._rpcWebSocketConnected = false;
|
|
7278
7376
|
this._rpcWebSocketGeneration++;
|
|
7279
7377
|
|
|
7280
7378
|
if (this._rpcWebSocketHeartbeat) {
|
|
@@ -9606,16 +9704,36 @@ VoteProgram.space = 3731;
|
|
|
9606
9704
|
*
|
|
9607
9705
|
* @param {Connection} connection
|
|
9608
9706
|
* @param {Buffer} rawTransaction
|
|
9707
|
+
* @param {BlockheightBasedTransactionConfimationStrategy} confirmationStrategy
|
|
9609
9708
|
* @param {ConfirmOptions} [options]
|
|
9610
9709
|
* @returns {Promise<TransactionSignature>}
|
|
9611
9710
|
*/
|
|
9612
|
-
|
|
9711
|
+
|
|
9712
|
+
/**
|
|
9713
|
+
* @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
|
|
9714
|
+
* is no longer supported and will be removed in a future version.
|
|
9715
|
+
*/
|
|
9716
|
+
// eslint-disable-next-line no-redeclare
|
|
9717
|
+
// eslint-disable-next-line no-redeclare
|
|
9718
|
+
async function sendAndConfirmRawTransaction(connection, rawTransaction, confirmationStrategyOrConfirmOptions, maybeConfirmOptions) {
|
|
9719
|
+
let confirmationStrategy;
|
|
9720
|
+
let options;
|
|
9721
|
+
|
|
9722
|
+
if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'lastValidBlockHeight')) {
|
|
9723
|
+
confirmationStrategy = confirmationStrategyOrConfirmOptions;
|
|
9724
|
+
options = maybeConfirmOptions;
|
|
9725
|
+
} else {
|
|
9726
|
+
options = confirmationStrategyOrConfirmOptions;
|
|
9727
|
+
}
|
|
9728
|
+
|
|
9613
9729
|
const sendOptions = options && {
|
|
9614
9730
|
skipPreflight: options.skipPreflight,
|
|
9615
9731
|
preflightCommitment: options.preflightCommitment || options.commitment
|
|
9616
9732
|
};
|
|
9617
9733
|
const signature = await connection.sendRawTransaction(rawTransaction, sendOptions);
|
|
9618
|
-
const
|
|
9734
|
+
const commitment = options && options.commitment;
|
|
9735
|
+
const confirmationPromise = confirmationStrategy ? connection.confirmTransaction(confirmationStrategy, commitment) : connection.confirmTransaction(signature, commitment);
|
|
9736
|
+
const status = (await confirmationPromise).value;
|
|
9619
9737
|
|
|
9620
9738
|
if (status.err) {
|
|
9621
9739
|
throw new Error(`Raw transaction ${signature} failed (${JSON.stringify(status)})`);
|