chore: unify account fetching api

This commit is contained in:
Sebastian.Bor 2021-08-26 22:08:15 +02:00
parent cb137c1e8b
commit fe7bda34d8
4 changed files with 98 additions and 150 deletions

View File

@ -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<Realm>(
return getBorshProgramAccounts<Realm>(
rpcContext.programId,
GOVERNANCE_SCHEMA,
rpcContext.endpoint,
Realm,
GovernanceAccountType.Realm,
);
}
@ -28,23 +28,25 @@ export async function getGovernanceAccounts<TAccount extends GovernanceAccount>(
filters: MemcmpFilter[] = [],
) {
if (accountTypes.length === 1) {
return getGovernanceAccountsImpl<TAccount>(
return getBorshProgramAccounts<TAccount>(
programId,
GOVERNANCE_SCHEMA,
endpoint,
accountClass,
accountTypes[0],
accountClass as any,
filters,
accountTypes[0],
);
}
const all = await Promise.all(
accountTypes.map(at =>
getGovernanceAccountsImpl<TAccount>(
getBorshProgramAccounts<TAccount>(
programId,
GOVERNANCE_SCHEMA,
endpoint,
accountClass,
at,
accountClass as any,
filters,
at,
),
),
);
@ -54,66 +56,3 @@ export async function getGovernanceAccounts<TAccount extends GovernanceAccount>(
ParsedAccount<TAccount>
>;
}
async function getGovernanceAccountsImpl<TAccount extends GovernanceAccount>(
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<string, ParsedAccount<TAccount>> = {};
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;
}

View File

@ -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<ChatMessage>(
return getBorshProgramAccounts<ChatMessage>(
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<string, ParsedAccount<TAccount>> = {};
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;
}

View File

@ -0,0 +1,4 @@
// Interface for accounts with type field
export interface ProgramAccountWithType {
accountType: number;
}

View File

@ -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<TAccount> } = {};
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;
}