UNPKG

@drift-labs/sdk

Version:
90 lines (89 loc) 3.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BlockhashSubscriber = void 0; const web3_js_1 = require("@solana/web3.js"); class BlockhashSubscriber { constructor(config) { var _a, _b; this.isSubscribed = false; this.blockhashes = []; if (!config.connection && !config.rpcUrl) { throw new Error('BlockhashSubscriber requires one of connection or rpcUrl must be provided'); } this.connection = config.connection || new web3_js_1.Connection(config.rpcUrl); this.commitment = (_a = config.commitment) !== null && _a !== void 0 ? _a : 'confirmed'; this.updateIntervalMs = (_b = config.updateIntervalMs) !== null && _b !== void 0 ? _b : 1000; } getBlockhashCacheSize() { return this.blockhashes.length; } getLatestBlockHeight() { return this.latestBlockHeight; } getLatestBlockHeightContext() { return this.latestBlockHeightContext; } /** * Returns the latest cached blockhash, based on an offset from the latest obtained * @param offset Offset to use, defaulting to 0 * @param offsetType If 'seconds', it will use calculate the actual element offset based on the update interval; otherwise it will return a fixed index * @returns Cached blockhash at the given offset, or undefined */ getLatestBlockhash(offset = 0, offsetType = 'index') { if (this.blockhashes.length === 0) { return undefined; } const elementOffset = offsetType == 'seconds' ? Math.floor((offset * 1000) / this.updateIntervalMs) : offset; const clampedOffset = Math.max(0, Math.min(this.blockhashes.length - 1, elementOffset)); return this.blockhashes[this.blockhashes.length - 1 - clampedOffset]; } pruneBlockhashes() { if (this.latestBlockHeight) { this.blockhashes = this.blockhashes.filter((blockhash) => blockhash.lastValidBlockHeight > this.latestBlockHeight); } } async updateBlockhash() { try { const [resp, lastConfirmedBlockHeight] = await Promise.all([ this.connection.getLatestBlockhashAndContext({ commitment: this.commitment, }), this.connection.getBlockHeight({ commitment: this.commitment }), ]); this.latestBlockHeight = lastConfirmedBlockHeight; this.latestBlockHeightContext = resp.context; // avoid caching duplicate blockhashes if (this.blockhashes.length > 0) { if (resp.value.blockhash === this.blockhashes[this.blockhashes.length - 1].blockhash) { return; } } this.blockhashes.push(resp.value); } catch (e) { console.error('Error updating blockhash:\n', e); } finally { this.pruneBlockhashes(); } } async subscribe() { if (this.isSubscribed) { return; } this.isSubscribed = true; await this.updateBlockhash(); this.updateBlockhashIntervalId = setInterval(this.updateBlockhash.bind(this), this.updateIntervalMs); } unsubscribe() { if (this.updateBlockhashIntervalId) { clearInterval(this.updateBlockhashIntervalId); this.updateBlockhashIntervalId = undefined; } this.isSubscribed = false; } } exports.BlockhashSubscriber = BlockhashSubscriber;