@drift-labs/sdk
Version:
SDK for Drift Protocol
90 lines (89 loc) • 3.58 kB
JavaScript
"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;