UNPKG

@drift-labs/sdk-browser

Version:
182 lines (181 loc) 7.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReferrerMap = void 0; const web3_js_1 = require("@solana/web3.js"); const pda_1 = require("../addresses/pda"); const memcmp_1 = require("../memcmp"); const bytes_1 = require("@coral-xyz/anchor/dist/cjs/utils/bytes"); const DEFAULT_PUBLIC_KEY = web3_js_1.PublicKey.default.toBase58(); class ReferrerMap { /** * Creates a new UserStatsMap instance. * * @param {DriftClient} driftClient - The DriftClient instance. */ constructor(driftClient, parallelSync) { /** * map from authority pubkey to referrer pubkey. */ this.authorityReferrerMap = new Map(); /** * map from referrer pubkey to ReferrerInfo. * Will be undefined if the referrer is not in the map yet. */ this.referrerReferrerInfoMap = new Map(); this.driftClient = driftClient; this.parallelSync = parallelSync !== undefined ? parallelSync : true; } /** * Subscribe to all UserStats accounts. */ async subscribe() { if (this.size() > 0) { return; } await this.driftClient.subscribe(); await this.sync(); } has(authorityPublicKey) { return this.authorityReferrerMap.has(authorityPublicKey); } get(authorityPublicKey) { return this.getReferrer(authorityPublicKey); } async addReferrer(authority, referrer) { if (referrer) { this.authorityReferrerMap.set(authority, referrer); } else if (referrer === undefined) { const userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, new web3_js_1.PublicKey(authority)); const buffer = (await this.driftClient.connection.getAccountInfo(userStatsAccountPublicKey, 'processed')).data; const referrer = bytes_1.bs58.encode(buffer.subarray(40, 72)); this.addReferrer(authority, referrer); } } /** * Enforce that a UserStats will exist for the given authorityPublicKey, * reading one from the blockchain if necessary. * @param authorityPublicKey * @returns */ async mustGet(authorityPublicKey) { if (!this.has(authorityPublicKey)) { await this.addReferrer(authorityPublicKey); } return this.getReferrer(authorityPublicKey); } getReferrer(authorityPublicKey) { const referrer = this.authorityReferrerMap.get(authorityPublicKey); if (!referrer) { // return undefined if the referrer is not in the map return undefined; } if (referrer === DEFAULT_PUBLIC_KEY) { return undefined; } if (this.referrerReferrerInfoMap.has(referrer)) { return this.referrerReferrerInfoMap.get(referrer); } const referrerKey = new web3_js_1.PublicKey(referrer); const referrerInfo = { referrer: (0, pda_1.getUserAccountPublicKeySync)(this.driftClient.program.programId, referrerKey, 0), referrerStats: (0, pda_1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, referrerKey), }; this.referrerReferrerInfoMap.set(referrer, referrerInfo); return referrerInfo; } size() { return this.authorityReferrerMap.size; } numberOfReferred() { return Array.from(this.authorityReferrerMap.values()).filter((referrer) => referrer !== DEFAULT_PUBLIC_KEY).length; } async sync() { if (this.fetchPromise) { return this.fetchPromise; } this.fetchPromise = new Promise((resolver) => { this.fetchPromiseResolver = resolver; }); try { if (this.parallelSync) { await Promise.all([ this.syncAll(), this.syncReferrer((0, memcmp_1.getUserStatsIsReferredFilter)()), this.syncReferrer((0, memcmp_1.getUserStatsIsReferredOrReferrerFilter)()), ]); } else { await this.syncAll(); await this.syncReferrer((0, memcmp_1.getUserStatsIsReferredFilter)()); await this.syncReferrer((0, memcmp_1.getUserStatsIsReferredOrReferrerFilter)()); } } finally { this.fetchPromiseResolver(); this.fetchPromise = undefined; } } async syncAll() { const rpcRequestArgs = [ this.driftClient.program.programId.toBase58(), { commitment: this.driftClient.opts.commitment, filters: [(0, memcmp_1.getUserStatsFilter)()], encoding: 'base64', dataSlice: { offset: 0, length: 0, }, withContext: true, }, ]; const rpcJSONResponse = // @ts-ignore await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs); const rpcResponseAndContext = rpcJSONResponse.result; for (const account of rpcResponseAndContext.value) { // only add if it isn't already in the map // so that if syncReferrer already set it, we dont overwrite if (!this.has(account.pubkey)) { this.addReferrer(account.pubkey, DEFAULT_PUBLIC_KEY); } } } async syncReferrer(referrerFilter) { const rpcRequestArgs = [ this.driftClient.program.programId.toBase58(), { commitment: this.driftClient.opts.commitment, filters: [(0, memcmp_1.getUserStatsFilter)(), referrerFilter], encoding: 'base64', dataSlice: { offset: 0, length: 72, }, withContext: true, }, ]; const rpcJSONResponse = // @ts-ignore await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs); const rpcResponseAndContext = rpcJSONResponse.result; const batchSize = 1000; for (let i = 0; i < rpcResponseAndContext.value.length; i += batchSize) { const batch = rpcResponseAndContext.value.slice(i, i + batchSize); await Promise.all(batch.map(async (programAccount) => { // @ts-ignore const buffer = Buffer.from(programAccount.account.data[0], programAccount.account.data[1]); const authority = bytes_1.bs58.encode(buffer.subarray(8, 40)); const referrer = bytes_1.bs58.encode(buffer.subarray(40, 72)); this.addReferrer(authority, referrer); })); await new Promise((resolve) => setTimeout(resolve, 0)); } } async unsubscribe() { this.authorityReferrerMap.clear(); this.referrerReferrerInfoMap.clear(); } } exports.ReferrerMap = ReferrerMap;