@drift-labs/sdk-browser
Version:
SDK for Drift Protocol
169 lines (168 loc) • 7.4 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WhileValidTxSender = void 0;
const types_1 = require("./types");
const web3_js_1 = require("@solana/web3.js");
const baseTxSender_1 = require("./baseTxSender");
const bs58_1 = __importDefault(require("bs58"));
const config_1 = require("../config");
const DEFAULT_RETRY = 2000;
class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
async checkAndSetUseBlockHeightOffset() {
this.connection.getVersion().then((version) => {
const solanaCoreVersion = version['solana-core'];
if (!solanaCoreVersion)
return;
const majorVersion = solanaCoreVersion.split('.')[0];
if (!majorVersion)
return;
const parsedMajorVersion = parseInt(majorVersion);
if (isNaN(parsedMajorVersion))
return;
if (parsedMajorVersion >= 2) {
this.useBlockHeightOffset = false;
}
else {
this.useBlockHeightOffset = true;
}
});
}
constructor({ connection, wallet, opts = { ...config_1.DEFAULT_CONFIRMATION_OPTS, maxRetries: 0 }, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks = [], txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, throwOnTimeoutError = true, throwOnTransactionError = true, }) {
super({
connection,
wallet,
opts,
additionalConnections,
additionalTxSenderCallbacks,
txHandler,
trackTxLandRate,
txLandRateLookbackWindowMinutes,
confirmationStrategy,
landRateToFeeFunc,
throwOnTimeoutError,
throwOnTransactionError,
});
this.timoutCount = 0;
this.untilValid = new Map();
this.useBlockHeightOffset = true;
this.retrySleep = retrySleep;
this.checkAndSetUseBlockHeightOffset();
}
async sleep(reference) {
return new Promise((resolve) => {
reference.resolve = resolve;
setTimeout(resolve, this.retrySleep);
});
}
async prepareTx(tx, additionalSigners, opts, preSigned) {
var _a;
let latestBlockhash = await this.txHandler.getLatestBlockhashForTransaction();
// handle tx
let signedTx = tx;
if (!preSigned) {
signedTx = await this.txHandler.prepareTx(tx, additionalSigners, undefined, opts, false, latestBlockhash);
}
// See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
// @ts-ignore
if (preSigned && tx.SIGNATURE_BLOCK_AND_EXPIRY) {
// @ts-ignore
latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
}
// handle subclass-specific side effects
const txSig = bs58_1.default.encode((signedTx === null || signedTx === void 0 ? void 0 : signedTx.signature) || ((_a = signedTx.signatures[0]) === null || _a === void 0 ? void 0 : _a.signature));
this.untilValid.set(txSig, latestBlockhash);
return signedTx;
}
async sendVersionedTransaction(tx, additionalSigners, opts, preSigned) {
let latestBlockhash = await this.txHandler.getLatestBlockhashForTransaction();
let signedTx;
if (preSigned) {
signedTx = tx;
// See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
// @ts-ignore
if (tx.SIGNATURE_BLOCK_AND_EXPIRY) {
// @ts-ignore
latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
}
// @ts-ignore
}
else if (this.wallet.payer) {
tx.message.recentBlockhash = latestBlockhash.blockhash;
// @ts-ignore
tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.wallet.payer));
signedTx = tx;
}
else {
tx.message.recentBlockhash = latestBlockhash.blockhash;
additionalSigners === null || additionalSigners === void 0 ? void 0 : additionalSigners.filter((s) => s !== undefined).forEach((kp) => {
tx.sign([kp]);
});
signedTx = await this.txHandler.signVersionedTx(tx, additionalSigners, latestBlockhash);
}
if (opts === undefined) {
opts = this.opts;
}
const txSig = bs58_1.default.encode(signedTx.signatures[0]);
this.untilValid.set(txSig, latestBlockhash);
return this.sendRawTransaction(signedTx.serialize(), opts);
}
async sendRawTransaction(rawTransaction, opts) {
var _a, _b, _c, _d;
const startTime = this.getTimestamp();
const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
(_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(txid, false);
this.sendToAdditionalConnections(rawTransaction, opts);
let done = false;
const resolveReference = {
resolve: undefined,
};
const stopWaiting = () => {
done = true;
if (resolveReference.resolve) {
resolveReference.resolve();
}
};
(async () => {
while (!done && this.getTimestamp() - startTime < this.timeout) {
await this.sleep(resolveReference);
if (!done) {
this.connection
.sendRawTransaction(rawTransaction, opts)
.catch((e) => {
console.error(e);
stopWaiting();
});
this.sendToAdditionalConnections(rawTransaction, opts);
}
}
})();
let slot;
try {
const result = await this.confirmTransaction(txid, opts.commitment);
(_b = this.txSigCache) === null || _b === void 0 ? void 0 : _b.set(txid, true);
await this.checkConfirmationResultForError(txid, result === null || result === void 0 ? void 0 : result.value);
if (((_c = result === null || result === void 0 ? void 0 : result.value) === null || _c === void 0 ? void 0 : _c.err) && this.throwOnTransactionError) {
// Fallback error handling if there's a problem reporting the error in checkConfirmationResultForError
throw new web3_js_1.SendTransactionError({
action: 'send',
signature: txid,
transactionMessage: `Transaction Failed`,
});
}
slot = (_d = result === null || result === void 0 ? void 0 : result.context) === null || _d === void 0 ? void 0 : _d.slot;
// eslint-disable-next-line no-useless-catch
}
catch (e) {
throw e;
}
finally {
stopWaiting();
this.untilValid.delete(txid);
}
return { txSig: txid, slot };
}
}
exports.WhileValidTxSender = WhileValidTxSender;
;