106 lines
2.7 KiB
TypeScript
106 lines
2.7 KiB
TypeScript
// TODO: replace this whole file with something more modern. This is all copied
|
|
// from sollet..
|
|
|
|
import * as BufferLayout from "buffer-layout";
|
|
import { BN } from "@project-serum/anchor";
|
|
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
|
import { Connection, PublicKey } from "@solana/web3.js";
|
|
import * as bs58 from "bs58";
|
|
|
|
export async function getOwnedTokenAccounts(
|
|
connection: Connection,
|
|
publicKey: PublicKey
|
|
) {
|
|
let filters = getOwnedAccountsFilters(publicKey);
|
|
// @ts-ignore
|
|
let resp = await connection._rpcRequest("getProgramAccounts", [
|
|
TOKEN_PROGRAM_ID.toBase58(),
|
|
{
|
|
commitment: connection.commitment,
|
|
filters,
|
|
},
|
|
]);
|
|
if (resp.error) {
|
|
throw new Error(
|
|
"failed to get token accounts owned by " +
|
|
publicKey.toBase58() +
|
|
": " +
|
|
resp.error.message
|
|
);
|
|
}
|
|
return resp.result
|
|
.map(({ pubkey, account: { data, executable, owner, lamports } }: any) => ({
|
|
publicKey: new PublicKey(pubkey),
|
|
accountInfo: {
|
|
data: bs58.decode(data),
|
|
executable,
|
|
owner: new PublicKey(owner),
|
|
lamports,
|
|
},
|
|
}))
|
|
.filter(({ accountInfo }: any) => {
|
|
// TODO: remove this check once mainnet is updated
|
|
return filters.every((filter) => {
|
|
if (filter.dataSize) {
|
|
return accountInfo.data.length === filter.dataSize;
|
|
} else if (filter.memcmp) {
|
|
let filterBytes = bs58.decode(filter.memcmp.bytes);
|
|
return accountInfo.data
|
|
.slice(
|
|
filter.memcmp.offset,
|
|
filter.memcmp.offset + filterBytes.length
|
|
)
|
|
.equals(filterBytes);
|
|
}
|
|
return false;
|
|
});
|
|
})
|
|
.map(({ publicKey, accountInfo }: any) => {
|
|
return { publicKey, account: parseTokenAccountData(accountInfo.data) };
|
|
});
|
|
}
|
|
|
|
export const ACCOUNT_LAYOUT = BufferLayout.struct([
|
|
BufferLayout.blob(32, "mint"),
|
|
BufferLayout.blob(32, "owner"),
|
|
BufferLayout.nu64("amount"),
|
|
BufferLayout.blob(93),
|
|
]);
|
|
|
|
export const MINT_LAYOUT = BufferLayout.struct([
|
|
BufferLayout.blob(44),
|
|
BufferLayout.u8("decimals"),
|
|
BufferLayout.blob(37),
|
|
]);
|
|
|
|
export function parseTokenAccountData(data: Buffer) {
|
|
// @ts-ignore
|
|
let { mint, owner, amount } = ACCOUNT_LAYOUT.decode(data);
|
|
return {
|
|
mint: new PublicKey(mint),
|
|
owner: new PublicKey(owner),
|
|
amount: new BN(amount),
|
|
};
|
|
}
|
|
|
|
export function parseMintData(data: Buffer) {
|
|
// @ts-ignore
|
|
let { decimals } = MINT_LAYOUT.decode(data);
|
|
return { decimals };
|
|
}
|
|
|
|
function getOwnedAccountsFilters(publicKey: PublicKey) {
|
|
return [
|
|
{
|
|
memcmp: {
|
|
// @ts-ignore
|
|
offset: ACCOUNT_LAYOUT.offsetOf("owner"),
|
|
bytes: publicKey.toBase58(),
|
|
},
|
|
},
|
|
{
|
|
dataSize: ACCOUNT_LAYOUT.span,
|
|
},
|
|
];
|
|
}
|