import { AccountInfo, Connection, PublicKey } from "@solana/web3.js"; import { u64, AccountLayout, TOKEN_PROGRAM_ID, AccountInfo as TokenAccountInfo, } from "@solana/spl-token"; import { truthy } from "./truthy"; export const deserializeAccount = (data: Buffer) => { const accountInfo = AccountLayout.decode(data); accountInfo.mint = new PublicKey(accountInfo.mint); accountInfo.owner = new PublicKey(accountInfo.owner); accountInfo.amount = u64.fromBuffer(accountInfo.amount); if (accountInfo.delegateOption === 0) { accountInfo.delegate = null; accountInfo.delegatedAmount = new u64(0); } else { accountInfo.delegate = new PublicKey(accountInfo.delegate); accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount); } accountInfo.isInitialized = accountInfo.state !== 0; accountInfo.isFrozen = accountInfo.state === 2; if (accountInfo.isNativeOption === 1) { accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative); accountInfo.isNative = true; } else { accountInfo.rentExemptReserve = null; accountInfo.isNative = false; } if (accountInfo.closeAuthorityOption === 0) { accountInfo.closeAuthority = null; } else { accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority); } return accountInfo; }; export interface TokenAccount { pubkey: PublicKey; account: AccountInfo; info: TokenAccountInfo; } export const TokenAccountParser = ( pubKey: PublicKey, info: AccountInfo ): TokenAccount | undefined => { // Sometimes a wrapped sol account gets closed, goes to 0 length, // triggers an update over wss which triggers this guy to get called // since your UI already logged that pubkey as a token account. Check for length. if (info.data.length > 0) { const buffer = Buffer.from(info.data); const data = deserializeAccount(buffer); const details = { pubkey: pubKey, account: { ...info, }, info: data, } as TokenAccount; return details; } }; export const getWalletTokenAccounts = async ( connection: Connection, owner?: PublicKey ): Promise => { if (!owner) { return []; } // user accounts are updated via ws subscription const accounts = await connection.getTokenAccountsByOwner(owner, { programId: TOKEN_PROGRAM_ID, }); const tokenAccounts = accounts.value .map((info) => TokenAccountParser(info.pubkey, info.account)) .filter(truthy) .filter((t) => t.info.amount.gt(new u64(0))); return tokenAccounts; };