UNPKG

@drift-labs/sdk-browser

Version:
178 lines (177 loc) 7.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConstituentMap = void 0; const pollingConstituentAccountSubscriber_1 = require("./pollingConstituentAccountSubscriber"); const webSocketConstituentAccountSubscriber_1 = require("./webSocketConstituentAccountSubscriber"); const memcmp_1 = require("../memcmp"); const zstddec_1 = require("zstddec"); const pda_1 = require("../addresses/pda"); const MAX_CONSTITUENT_SIZE_BYTES = 480; // TODO: update this when account is finalized class ConstituentMap { constructor(config) { var _a, _b; this.constituentMap = new Map(); this.constituentIndexToKeyMap = new Map(); this.spotMarketIndexToKeyMap = new Map(); this.driftClient = config.driftClient; this.additionalFilters = config.additionalFilters; this.commitment = config.subscriptionConfig.commitment; this.connection = config.connection || this.driftClient.connection; this.lpPoolId = (_a = config.lpPoolId) !== null && _a !== void 0 ? _a : 0; this.decoder = (_b = config.decoder) !== null && _b !== void 0 ? _b : 'base64+zstd'; if (config.subscriptionConfig.type === 'polling') { this.constituentAccountSubscriber = new pollingConstituentAccountSubscriber_1.PollingConstituentAccountSubscriber(this, this.driftClient.program, config.subscriptionConfig.frequency, config.subscriptionConfig.commitment, this.getFilters()); } else if (config.subscriptionConfig.type === 'websocket') { this.constituentAccountSubscriber = new webSocketConstituentAccountSubscriber_1.WebSocketConstituentAccountSubscriber(this, this.driftClient.program, config.subscriptionConfig.resubTimeoutMs, config.subscriptionConfig.commitment, this.getFilters()); } // Listen for account updates from the subscriber this.constituentAccountSubscriber.eventEmitter.on('onAccountUpdate', (account, pubkey, slot) => { this.updateConstituentAccount(pubkey.toString(), account, slot); }); } getFilters() { const filters = [ (0, memcmp_1.getConstituentFilter)(), (0, memcmp_1.getConstituentLpPoolFilter)((0, pda_1.getLpPoolPublicKey)(this.driftClient.program.programId, this.lpPoolId)), ]; if (this.additionalFilters) { filters.push(...this.additionalFilters); } return filters; } decode(name, buffer) { return this.driftClient.program.account.constituent.coder.accounts.decodeUnchecked(name, buffer); } async sync() { try { const rpcRequestArgs = [ this.driftClient.program.programId.toBase58(), { commitment: this.commitment, filters: this.getFilters(), encoding: this.decoder, withContext: true, }, ]; // @ts-ignore const rpcJSONResponse = await this.connection._rpcRequest('getProgramAccounts', rpcRequestArgs); const rpcResponseAndContext = rpcJSONResponse.result; const slot = rpcResponseAndContext.context.slot; const promises = rpcResponseAndContext.value.map(async (programAccount) => { let buffer; if (this.decoder === 'base64+zstd') { const compressedUserData = Buffer.from(programAccount.account.data[0], 'base64'); const decoder = new zstddec_1.ZSTDDecoder(); await decoder.init(); buffer = Buffer.from(decoder.decode(compressedUserData, MAX_CONSTITUENT_SIZE_BYTES)); } else { buffer = Buffer.from(programAccount.account.data[0], 'base64'); } const key = programAccount.pubkey.toString(); const currAccountWithSlot = this.getWithSlot(key); if (currAccountWithSlot) { if (slot >= currAccountWithSlot.slot) { const constituentAcc = this.decode('Constituent', buffer); this.updateConstituentAccount(key, constituentAcc, slot); } } else { const constituentAcc = this.decode('Constituent', buffer); this.updateConstituentAccount(key, constituentAcc, slot); } }); await Promise.all(promises); } catch (error) { console.log(`ConstituentMap.sync() error: ${error.message}`); } } async subscribe() { await this.constituentAccountSubscriber.subscribe(); } async unsubscribe() { await this.constituentAccountSubscriber.unsubscribe(); this.constituentMap.clear(); } has(key) { return this.constituentMap.has(key); } get(key) { var _a; return (_a = this.constituentMap.get(key)) === null || _a === void 0 ? void 0 : _a.data; } getFromConstituentIndex(constituentIndex) { const key = this.constituentIndexToKeyMap.get(constituentIndex); return key ? this.get(key) : undefined; } getFromSpotMarketIndex(spotMarketIndex) { const key = this.spotMarketIndexToKeyMap.get(spotMarketIndex); return key ? this.get(key) : undefined; } getWithSlot(key) { return this.constituentMap.get(key); } async mustGet(key) { if (!this.has(key)) { await this.sync(); } const result = this.constituentMap.get(key); if (!result) { throw new Error(`ConstituentAccount not found for key: ${key}`); } return result.data; } async mustGetWithSlot(key) { if (!this.has(key)) { await this.sync(); } const result = this.constituentMap.get(key); if (!result) { throw new Error(`ConstituentAccount not found for key: ${key}`); } return result; } size() { return this.constituentMap.size; } *values() { for (const dataAndSlot of this.constituentMap.values()) { yield dataAndSlot.data; } } valuesWithSlot() { return this.constituentMap.values(); } *entries() { for (const [key, dataAndSlot] of this.constituentMap.entries()) { yield [key, dataAndSlot.data]; } } entriesWithSlot() { return this.constituentMap.entries(); } updateConstituentAccount(key, constituentAccount, slot) { const existingData = this.getWithSlot(key); if (existingData) { if (slot >= existingData.slot) { this.constituentMap.set(key, { data: constituentAccount, slot, }); } } else { this.constituentMap.set(key, { data: constituentAccount, slot, }); } this.constituentIndexToKeyMap.set(constituentAccount.constituentIndex, key); this.spotMarketIndexToKeyMap.set(constituentAccount.spotMarketIndex, key); } } exports.ConstituentMap = ConstituentMap;