diff --git a/packages/governance/src/models/api.ts b/packages/governance/src/models/api.ts index cb0692a..d6f458d 100644 --- a/packages/governance/src/models/api.ts +++ b/packages/governance/src/models/api.ts @@ -1,6 +1,6 @@ import { PublicKey } from '@solana/web3.js'; -import * as bs58 from 'bs58'; -import { deserializeBorsh, ParsedAccount } from '@oyster/common'; + +import { ParsedAccount } from '@oyster/common'; import { GOVERNANCE_SCHEMA } from './serialisation'; import { GovernanceAccount, @@ -9,14 +9,14 @@ import { Realm, } from './accounts'; -import { MemcmpFilter, RpcContext } from './core/api'; +import { getBorshProgramAccounts, MemcmpFilter, RpcContext } from './core/api'; export async function getRealms(rpcContext: RpcContext) { - return getGovernanceAccountsImpl( + return getBorshProgramAccounts( rpcContext.programId, + GOVERNANCE_SCHEMA, rpcContext.endpoint, Realm, - GovernanceAccountType.Realm, ); } @@ -28,23 +28,25 @@ export async function getGovernanceAccounts( filters: MemcmpFilter[] = [], ) { if (accountTypes.length === 1) { - return getGovernanceAccountsImpl( + return getBorshProgramAccounts( programId, + GOVERNANCE_SCHEMA, endpoint, - accountClass, - accountTypes[0], + accountClass as any, filters, + accountTypes[0], ); } const all = await Promise.all( accountTypes.map(at => - getGovernanceAccountsImpl( + getBorshProgramAccounts( programId, + GOVERNANCE_SCHEMA, endpoint, - accountClass, - at, + accountClass as any, filters, + at, ), ), ); @@ -54,66 +56,3 @@ export async function getGovernanceAccounts( ParsedAccount >; } - -async function getGovernanceAccountsImpl( - programId: PublicKey, - endpoint: string, - accountClass: GovernanceAccountClass, - accountType: GovernanceAccountType, - filters: MemcmpFilter[] = [], -) { - let getProgramAccounts = await fetch(endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - jsonrpc: '2.0', - id: 1, - method: 'getProgramAccounts', - params: [ - programId.toBase58(), - { - commitment: 'single', - encoding: 'base64', - filters: [ - { - memcmp: { - offset: 0, - bytes: bs58.encode([accountType]), - }, - }, - ...filters.map(f => ({ - memcmp: { offset: f.offset, bytes: bs58.encode(f.bytes) }, - })), - ], - }, - ], - }), - }); - const rawAccounts = (await getProgramAccounts.json())['result']; - let accounts: Record> = {}; - - for (let rawAccount of rawAccounts) { - try { - const account = { - pubkey: new PublicKey(rawAccount.pubkey), - account: { - ...rawAccount.account, - data: [], // There is no need to keep the raw data around once we deserialize it into TAccount - }, - info: deserializeBorsh( - GOVERNANCE_SCHEMA, - accountClass, - Buffer.from(rawAccount.account.data[0], 'base64'), - ), - }; - - accounts[account.pubkey.toBase58()] = account; - } catch (ex) { - console.error(`Can't deserialize ${accountClass}`, ex); - } - } - - return accounts; -} diff --git a/packages/governance/src/models/chat/api.ts b/packages/governance/src/models/chat/api.ts index 57fbf2e..dc22182 100644 --- a/packages/governance/src/models/chat/api.ts +++ b/packages/governance/src/models/chat/api.ts @@ -1,90 +1,23 @@ import { PublicKey } from '@solana/web3.js'; -import bs58 from 'bs58'; -import { MemcmpFilter, pubkeyFilter } from '../core/api'; + import { - ChatMessage, - GovernanceChatAccount, - GovernanceChatAccountClass, - GovernanceChatAccountType, - governanceChatProgramId, -} from './accounts'; -import { deserializeBorsh, ParsedAccount } from '@oyster/common'; + getBorshProgramAccounts, + MemcmpFilter, + pubkeyFilter, +} from '../core/api'; +import { ChatMessage, governanceChatProgramId } from './accounts'; + import { GOVERNANCE_CHAT_SCHEMA } from './serialisation'; export function getGovernanceChatMessages( endpoint: string, proposal: PublicKey, ) { - return getGovernanceChatAccounts( + return getBorshProgramAccounts( governanceChatProgramId, + GOVERNANCE_CHAT_SCHEMA, endpoint, ChatMessage, - GovernanceChatAccountType.ChatMessage, [pubkeyFilter(1, proposal) as MemcmpFilter], ); } - -export async function getGovernanceChatAccounts< - TAccount extends GovernanceChatAccount ->( - programId: PublicKey, - endpoint: string, - accountClass: GovernanceChatAccountClass, - accountType: GovernanceChatAccountType, - filters: MemcmpFilter[] = [], -) { - let getProgramAccounts = await fetch(endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - jsonrpc: '2.0', - id: 1, - method: 'getProgramAccounts', - params: [ - programId.toBase58(), - { - commitment: 'single', - encoding: 'base64', - filters: [ - { - memcmp: { - offset: 0, - bytes: bs58.encode([accountType]), - }, - }, - ...filters.map(f => ({ - memcmp: { offset: f.offset, bytes: bs58.encode(f.bytes) }, - })), - ], - }, - ], - }), - }); - const rawAccounts = (await getProgramAccounts.json())['result']; - let accounts: Record> = {}; - - for (let rawAccount of rawAccounts) { - try { - const account = { - pubkey: new PublicKey(rawAccount.pubkey), - account: { - ...rawAccount.account, - data: [], // There is no need to keep the raw data around once we deserialize it into TAccount - }, - info: deserializeBorsh( - GOVERNANCE_CHAT_SCHEMA, - accountClass, - Buffer.from(rawAccount.account.data[0], 'base64'), - ), - }; - - accounts[account.pubkey.toBase58()] = account; - } catch (ex) { - console.error(`Can't deserialize ${accountClass}`, ex); - } - } - - return accounts; -} diff --git a/packages/governance/src/models/core/accounts.ts b/packages/governance/src/models/core/accounts.ts new file mode 100644 index 0000000..5ea2f59 --- /dev/null +++ b/packages/governance/src/models/core/accounts.ts @@ -0,0 +1,4 @@ +// Interface for accounts with type field +export interface ProgramAccountWithType { + accountType: number; +} diff --git a/packages/governance/src/models/core/api.ts b/packages/governance/src/models/core/api.ts index 02f5f95..9552519 100644 --- a/packages/governance/src/models/core/api.ts +++ b/packages/governance/src/models/core/api.ts @@ -1,5 +1,9 @@ import { Connection, PublicKey } from '@solana/web3.js'; import { WalletNotConnectedError } from '../errors'; +import bs58 from 'bs58'; +import { deserializeBorsh, ParsedAccount } from '@oyster/common'; +import { ProgramAccountWithType } from '../core/accounts'; +import { Schema } from 'borsh'; export interface IWallet { publicKey: PublicKey; @@ -63,3 +67,71 @@ export const pubkeyFilter = ( offset: number, pubkey: PublicKey | undefined | null, ) => (!pubkey ? undefined : new MemcmpFilter(offset, pubkey.toBuffer())); + +export async function getBorshProgramAccounts< + TAccount extends ProgramAccountWithType +>( + programId: PublicKey, + borshSchema: Schema, + endpoint: string, + accountFactory: new (args: any) => TAccount, + filters: MemcmpFilter[] = [], + accountType?: number, +) { + accountType = accountType ?? new accountFactory({}).accountType; + + let getProgramAccounts = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'getProgramAccounts', + params: [ + programId.toBase58(), + { + commitment: 'single', + encoding: 'base64', + filters: [ + { + memcmp: { + offset: 0, + bytes: bs58.encode([accountType]), + }, + }, + ...filters.map(f => ({ + memcmp: { offset: f.offset, bytes: bs58.encode(f.bytes) }, + })), + ], + }, + ], + }), + }); + const rawAccounts = (await getProgramAccounts.json())['result']; + let accounts: { [pubKey: string]: ParsedAccount } = {}; + + for (let rawAccount of rawAccounts) { + try { + const account = { + pubkey: new PublicKey(rawAccount.pubkey), + account: { + ...rawAccount.account, + data: [], // There is no need to keep the raw data around once we deserialize it into TAccount + }, + info: deserializeBorsh( + borshSchema, + accountFactory, + Buffer.from(rawAccount.account.data[0], 'base64'), + ), + }; + + accounts[account.pubkey.toBase58()] = account; + } catch (ex) { + console.error(`Can't deserialize ${accountFactory}`, ex); + } + } + + return accounts; +}