add getMultipleAccounts for Token (#2990)

* add getMultipleAccounts for Token

* update naming convention of fcn

* rename & reorg code

* lint fix

Co-authored-by: obiwan <you@example.com>
This commit is contained in:
Brennan Gebotys 2022-03-11 16:11:50 -05:00 committed by GitHub
parent 4ddaae5f21
commit a2bbabc1dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 54 additions and 25 deletions

View File

@ -1,6 +1,6 @@
import { struct, u32, u8 } from '@solana/buffer-layout'; import { struct, u32, u8 } from '@solana/buffer-layout';
import { publicKey, u64 } from '@solana/buffer-layout-utils'; import { publicKey, u64 } from '@solana/buffer-layout-utils';
import { Commitment, Connection, PublicKey } from '@solana/web3.js'; import { Commitment, Connection, PublicKey, AccountInfo } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from '../constants'; import { TOKEN_PROGRAM_ID } from '../constants';
import { import {
TokenAccountNotFoundError, TokenAccountNotFoundError,
@ -99,32 +99,32 @@ export async function getAccount(
programId = TOKEN_PROGRAM_ID programId = TOKEN_PROGRAM_ID
): Promise<Account> { ): Promise<Account> {
const info = await connection.getAccountInfo(address, commitment); const info = await connection.getAccountInfo(address, commitment);
if (!info) throw new TokenAccountNotFoundError(); return unpackAccount(info, address, programId);
if (!info.owner.equals(programId)) throw new TokenInvalidAccountOwnerError(); }
if (info.data.length < ACCOUNT_SIZE) throw new TokenInvalidAccountSizeError();
const rawAccount = AccountLayout.decode(info.data.slice(0, ACCOUNT_SIZE)); /**
let tlvData = Buffer.alloc(0); * Retrieve information about multiple token accounts in a single RPC call
if (info.data.length > ACCOUNT_SIZE) { *
if (info.data.length === MULTISIG_SIZE) throw new TokenInvalidAccountSizeError(); * @param connection Connection to use
if (info.data[ACCOUNT_SIZE] != AccountType.Account) throw new TokenInvalidAccountError(); * @param addresses Token accounts
tlvData = info.data.slice(ACCOUNT_SIZE + ACCOUNT_TYPE_SIZE); * @param commitment Desired level of commitment for querying the state
* @param programId SPL Token program account
*
* @return Token account information
*/
export async function getMultipleAccounts(
connection: Connection,
addresses: PublicKey[],
commitment?: Commitment,
programId = TOKEN_PROGRAM_ID
): Promise<Account[]> {
const infos = await connection.getMultipleAccountsInfo(addresses, commitment);
const accounts = [];
for (let i = 0; i < infos.length; i++) {
const account = unpackAccount(infos[i], addresses[i], programId);
accounts.push(account);
} }
return accounts;
return {
address,
mint: rawAccount.mint,
owner: rawAccount.owner,
amount: rawAccount.amount,
delegate: rawAccount.delegateOption ? rawAccount.delegate : null,
delegatedAmount: rawAccount.delegatedAmount,
isInitialized: rawAccount.state !== AccountState.Uninitialized,
isFrozen: rawAccount.state === AccountState.Frozen,
isNative: !!rawAccount.isNativeOption,
rentExemptReserve: rawAccount.isNativeOption ? rawAccount.isNative : null,
closeAuthority: rawAccount.closeAuthorityOption ? rawAccount.closeAuthority : null,
tlvData,
};
} }
/** Get the minimum lamport balance for a base token account to be rent exempt /** Get the minimum lamport balance for a base token account to be rent exempt
@ -156,3 +156,32 @@ export async function getMinimumBalanceForRentExemptAccountWithExtensions(
const accountLen = getAccountLen(extensions); const accountLen = getAccountLen(extensions);
return await connection.getMinimumBalanceForRentExemption(accountLen, commitment); return await connection.getMinimumBalanceForRentExemption(accountLen, commitment);
} }
function unpackAccount(info: AccountInfo<Buffer> | null, address: PublicKey, programId: PublicKey) {
if (!info) throw new TokenAccountNotFoundError();
if (!info.owner.equals(programId)) throw new TokenInvalidAccountOwnerError();
if (info.data.length < ACCOUNT_SIZE) throw new TokenInvalidAccountSizeError();
const rawAccount = AccountLayout.decode(info.data.slice(0, ACCOUNT_SIZE));
let tlvData = Buffer.alloc(0);
if (info.data.length > ACCOUNT_SIZE) {
if (info.data.length === MULTISIG_SIZE) throw new TokenInvalidAccountSizeError();
if (info.data[ACCOUNT_SIZE] != AccountType.Account) throw new TokenInvalidAccountError();
tlvData = info.data.slice(ACCOUNT_SIZE + ACCOUNT_TYPE_SIZE);
}
return {
address,
mint: rawAccount.mint,
owner: rawAccount.owner,
amount: rawAccount.amount,
delegate: rawAccount.delegateOption ? rawAccount.delegate : null,
delegatedAmount: rawAccount.delegatedAmount,
isInitialized: rawAccount.state !== AccountState.Uninitialized,
isFrozen: rawAccount.state === AccountState.Frozen,
isNative: !!rawAccount.isNativeOption,
rentExemptReserve: rawAccount.isNativeOption ? rawAccount.isNative : null,
closeAuthority: rawAccount.closeAuthorityOption ? rawAccount.closeAuthority : null,
tlvData,
};
}