UNPKG

@drift-labs/sdk-browser

Version:
169 lines (168 loc) 7.4 kB
"use strict"; 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;