swap-ui/src/utils/tokens.ts

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,
},
];
}