feat: add parsed account data APIs

This commit is contained in:
Justin Starry 2020-08-06 23:47:22 +08:00 committed by Justin Starry
parent b36e60738e
commit c7a2fbe7eb
5 changed files with 452 additions and 59 deletions

View File

@ -1,6 +1,7 @@
declare module 'superstruct' { declare module 'superstruct' {
declare type StructFunc = { declare type StructFunc = {
(any): any, (any): any,
object(schema: any): any;
union(schema: any): any; union(schema: any): any;
array(schema: any): any; array(schema: any): any;
literal(schema: any): any; literal(schema: any): any;

46
web3.js/module.d.ts vendored
View File

@ -104,16 +104,16 @@ declare module '@solana/web3.js' {
feeCalculator: FeeCalculator; feeCalculator: FeeCalculator;
}; };
export type PublicKeyAndAccount = { export type PublicKeyAndAccount<T> = {
pubkey: PublicKey; pubkey: PublicKey;
account: AccountInfo; account: AccountInfo<T>;
}; };
export type AccountInfo = { export type AccountInfo<T> = {
executable: boolean; executable: boolean;
owner: PublicKey; owner: PublicKey;
lamports: number; lamports: number;
data: Buffer; data: T;
rentEpoch?: number; rentEpoch?: number;
}; };
@ -181,9 +181,14 @@ declare module '@solana/web3.js' {
meta: ConfirmedTransactionMeta | null; meta: ConfirmedTransactionMeta | null;
}; };
export type ParsedAccountData = {
program: string;
parsed: any;
};
export type KeyedAccountInfo = { export type KeyedAccountInfo = {
accountId: PublicKey; accountId: PublicKey;
accountInfo: AccountInfo; accountInfo: AccountInfo<Buffer>;
}; };
export type Version = { export type Version = {
@ -210,7 +215,7 @@ declare module '@solana/web3.js' {
}; };
export type AccountChangeCallback = ( export type AccountChangeCallback = (
accountInfo: AccountInfo, accountInfo: AccountInfo<Buffer>,
context: Context, context: Context,
) => void; ) => void;
export type ProgramAccountChangeCallback = ( export type ProgramAccountChangeCallback = (
@ -280,15 +285,25 @@ declare module '@solana/web3.js' {
getAccountInfoAndContext( getAccountInfoAndContext(
publicKey: PublicKey, publicKey: PublicKey,
commitment?: Commitment, commitment?: Commitment,
): Promise<RpcResponseAndContext<AccountInfo | null>>; ): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>>;
getAccountInfo( getAccountInfo(
publicKey: PublicKey, publicKey: PublicKey,
commitment?: Commitment, commitment?: Commitment,
): Promise<AccountInfo | null>; ): Promise<AccountInfo<Buffer> | null>;
getParsedAccountInfo(
publicKey: PublicKey,
commitment?: Commitment,
): Promise<
RpcResponseAndContext<AccountInfo<Buffer | ParsedAccountData> | null>
>;
getProgramAccounts( getProgramAccounts(
programId: PublicKey, programId: PublicKey,
commitment?: Commitment, commitment?: Commitment,
): Promise<Array<PublicKeyAndAccount>>; ): Promise<Array<PublicKeyAndAccount<Buffer>>>;
getParsedProgramAccounts(
programId: PublicKey,
commitment?: Commitment,
): Promise<Array<PublicKeyAndAccount<Buffer | ParsedAccountData>>>;
getBalanceAndContext( getBalanceAndContext(
publicKey: PublicKey, publicKey: PublicKey,
commitment?: Commitment, commitment?: Commitment,
@ -311,7 +326,18 @@ declare module '@solana/web3.js' {
filter: TokenAccountsFilter, filter: TokenAccountsFilter,
commitment?: Commitment, commitment?: Commitment,
): Promise< ): Promise<
RpcResponseAndContext<Array<{pubkey: PublicKey; account: AccountInfo}>> RpcResponseAndContext<
Array<{pubkey: PublicKey; account: AccountInfo<Buffer>}>
>
>;
getParsedTokenAccountsByOwner(
ownerAddress: PublicKey,
filter: TokenAccountsFilter,
commitment?: Commitment,
): Promise<
RpcResponseAndContext<
Array<{pubkey: PublicKey; account: AccountInfo<ParsedAccountData>}>
>
>; >;
getLargestAccounts( getLargestAccounts(
config?: GetLargestAccountsConfig, config?: GetLargestAccountsConfig,

View File

@ -125,16 +125,16 @@ declare module '@solana/web3.js' {
feeCalculator: FeeCalculator, feeCalculator: FeeCalculator,
}; };
declare export type PublicKeyAndAccount = { declare export type PublicKeyAndAccount<T> = {
pubkey: PublicKey, pubkey: PublicKey,
account: AccountInfo, account: AccountInfo<T>,
}; };
declare export type AccountInfo = { declare export type AccountInfo<T> = {
executable: boolean, executable: boolean,
owner: PublicKey, owner: PublicKey,
lamports: number, lamports: number,
data: Buffer, data: T,
rentEpoch: number | null, rentEpoch: number | null,
}; };
@ -169,6 +169,11 @@ declare module '@solana/web3.js' {
meta: ConfirmedTransactionMeta | null, meta: ConfirmedTransactionMeta | null,
}; };
declare export type ParsedAccountData = {
program: string,
parsed: any,
};
declare export type ParsedMessageAccount = { declare export type ParsedMessageAccount = {
pubkey: PublicKey, pubkey: PublicKey,
signer: boolean, signer: boolean,
@ -204,7 +209,7 @@ declare module '@solana/web3.js' {
declare export type KeyedAccountInfo = { declare export type KeyedAccountInfo = {
accountId: PublicKey, accountId: PublicKey,
accountInfo: AccountInfo, accountInfo: AccountInfo<Buffer>,
}; };
declare export type Version = { declare export type Version = {
@ -231,7 +236,7 @@ declare module '@solana/web3.js' {
}; };
declare type AccountChangeCallback = ( declare type AccountChangeCallback = (
accountInfo: AccountInfo, accountInfo: AccountInfo<Buffer>,
context: Context, context: Context,
) => void; ) => void;
declare type ProgramAccountChangeCallback = ( declare type ProgramAccountChangeCallback = (
@ -301,15 +306,25 @@ declare module '@solana/web3.js' {
getAccountInfoAndContext( getAccountInfoAndContext(
publicKey: PublicKey, publicKey: PublicKey,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<RpcResponseAndContext<AccountInfo | null>>; ): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>>;
getAccountInfo( getAccountInfo(
publicKey: PublicKey, publicKey: PublicKey,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<AccountInfo | null>; ): Promise<AccountInfo<Buffer> | null>;
getParsedAccountInfo(
publicKey: PublicKey,
commitment: ?Commitment,
): Promise<
RpcResponseAndContext<AccountInfo<Buffer | ParsedAccountData> | null>,
>;
getProgramAccounts( getProgramAccounts(
programId: PublicKey, programId: PublicKey,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<Array<PublicKeyAndAccount>>; ): Promise<Array<PublicKeyAndAccount<Buffer>>>;
getParsedProgramAccounts(
programId: PublicKey,
commitment: ?Commitment,
): Promise<Array<PublicKeyAndAccount<Buffer | ParsedAccountData>>>;
getBalanceAndContext( getBalanceAndContext(
publicKey: PublicKey, publicKey: PublicKey,
commitment: ?Commitment, commitment: ?Commitment,
@ -332,7 +347,9 @@ declare module '@solana/web3.js' {
filter: TokenAccountsFilter, filter: TokenAccountsFilter,
commitment: ?Commitment, commitment: ?Commitment,
): Promise< ): Promise<
RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo}>>, RpcResponseAndContext<
Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>,
>,
>; >;
getLargestAccounts( getLargestAccounts(
config: ?GetLargestAccountsConfig, config: ?GetLargestAccountsConfig,

View File

@ -25,12 +25,12 @@ export const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
type RpcRequest = (methodName: string, args: Array<any>) => any; type RpcRequest = (methodName: string, args: Array<any>) => any;
type TokenAccountsFilter = type TokenAccountsFilter =
| { | {|
mint: PublicKey, mint: PublicKey,
} |}
| { | {|
programId: PublicKey, programId: PublicKey,
}; |};
/** /**
* Extra contextual information for RPC responses * Extra contextual information for RPC responses
@ -634,13 +634,34 @@ const GetTokenSupplyRpcResult = jsonRpcResultAndContext(TokenAmountResult);
*/ */
const GetTokenAccountsByOwner = jsonRpcResultAndContext( const GetTokenAccountsByOwner = jsonRpcResultAndContext(
struct.array([ struct.array([
struct({ struct.object({
pubkey: 'string', pubkey: 'string',
account: struct({ account: struct.object({
executable: 'boolean', executable: 'boolean',
owner: 'string', owner: 'string',
lamports: 'number', lamports: 'number',
data: 'any', data: 'string',
rentEpoch: 'number?',
}),
}),
]),
);
/**
* Expected JSON RPC response for the "getTokenAccountsByOwner" message with parsed data
*/
const GetParsedTokenAccountsByOwner = jsonRpcResultAndContext(
struct.array([
struct.object({
pubkey: 'string',
account: struct.object({
executable: 'boolean',
owner: 'string',
lamports: 'number',
data: struct.object({
program: 'string',
parsed: 'any',
}),
rentEpoch: 'number?', rentEpoch: 'number?',
}), }),
}), }),
@ -692,6 +713,23 @@ const AccountInfoResult = struct({
rentEpoch: 'number?', rentEpoch: 'number?',
}); });
/**
* @private
*/
const ParsedAccountInfoResult = struct.object({
executable: 'boolean',
owner: 'string',
lamports: 'number',
data: struct.union([
'string',
struct.object({
program: 'string',
parsed: 'any',
}),
]),
rentEpoch: 'number?',
});
/** /**
* Expected JSON RPC response for the "getAccountInfo" message * Expected JSON RPC response for the "getAccountInfo" message
*/ */
@ -699,6 +737,13 @@ const GetAccountInfoAndContextRpcResult = jsonRpcResultAndContext(
struct.union(['null', AccountInfoResult]), struct.union(['null', AccountInfoResult]),
); );
/**
* Expected JSON RPC response for the "getAccountInfo" message with jsonParsed param
*/
const GetParsedAccountInfoResult = jsonRpcResultAndContext(
struct.union(['null', ParsedAccountInfoResult]),
);
/** /**
* Expected JSON RPC response for the "getConfirmedSignaturesForAddress" message * Expected JSON RPC response for the "getConfirmedSignaturesForAddress" message
*/ */
@ -737,6 +782,14 @@ const ProgramAccountInfoResult = struct({
account: AccountInfoResult, account: AccountInfoResult,
}); });
/**
* @private
*/
const ParsedProgramAccountInfoResult = struct({
pubkey: 'string',
account: ParsedAccountInfoResult,
});
/*** /***
* Expected JSON RPC response for the "programNotification" message * Expected JSON RPC response for the "programNotification" message
*/ */
@ -785,6 +838,13 @@ const GetProgramAccountsRpcResult = jsonRpcResult(
struct.array([ProgramAccountInfoResult]), struct.array([ProgramAccountInfoResult]),
); );
/**
* Expected JSON RPC response for the "getProgramAccounts" message
*/
const GetParsedProgramAccountsRpcResult = jsonRpcResult(
struct.array([ParsedProgramAccountInfoResult]),
);
/** /**
* Expected JSON RPC response for the "getSlot" message * Expected JSON RPC response for the "getSlot" message
*/ */
@ -1051,20 +1111,32 @@ type SlotInfo = {
root: number, root: number,
}; };
/**
* Parsed account data
*
* @typedef {Object} ParsedAccountData
* @property {string} program Name of the program that owns this account
* @property {any} parsed Parsed account data
*/
type ParsedAccountData = {
program: string,
parsed: any,
};
/** /**
* Information describing an account * Information describing an account
* *
* @typedef {Object} AccountInfo * @typedef {Object} AccountInfo
* @property {number} lamports Number of lamports assigned to the account * @property {number} lamports Number of lamports assigned to the account
* @property {PublicKey} owner Identifier of the program that owns the account * @property {PublicKey} owner Identifier of the program that owns the account
* @property {?Buffer} data Optional data assigned to the account * @property {T} data Optional data assigned to the account
* @property {boolean} executable `true` if this account's data contains a loaded program * @property {boolean} executable `true` if this account's data contains a loaded program
*/ */
type AccountInfo = { type AccountInfo<T> = {
executable: boolean, executable: boolean,
owner: PublicKey, owner: PublicKey,
lamports: number, lamports: number,
data: Buffer, data: T,
}; };
/** /**
@ -1072,18 +1144,18 @@ type AccountInfo = {
* *
* @typedef {Object} KeyedAccountInfo * @typedef {Object} KeyedAccountInfo
* @property {PublicKey} accountId * @property {PublicKey} accountId
* @property {AccountInfo} accountInfo * @property {AccountInfo<Buffer>} accountInfo
*/ */
type KeyedAccountInfo = { type KeyedAccountInfo = {
accountId: PublicKey, accountId: PublicKey,
accountInfo: AccountInfo, accountInfo: AccountInfo<Buffer>,
}; };
/** /**
* Callback function for account change notifications * Callback function for account change notifications
*/ */
export type AccountChangeCallback = ( export type AccountChangeCallback = (
accountInfo: AccountInfo, accountInfo: AccountInfo<Buffer>,
context: Context, context: Context,
) => void; ) => void;
@ -1450,25 +1522,23 @@ export class Connection {
/** /**
* Fetch all the token accounts owned by the specified account * Fetch all the token accounts owned by the specified account
* *
* @return {Promise<RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo}>>>} * @return {Promise<RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>>>}
*/ */
async getTokenAccountsByOwner( async getTokenAccountsByOwner(
ownerAddress: PublicKey, ownerAddress: PublicKey,
filter: TokenAccountsFilter, filter: TokenAccountsFilter,
commitment: ?Commitment, commitment: ?Commitment,
): Promise< ): Promise<
RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo}>>, RpcResponseAndContext<
Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>,
>,
> { > {
let _args = [ownerAddress.toBase58()]; let _args = [ownerAddress.toBase58()];
if (filter.mint) {
// Strip flow types to make flow happy
((filter: any) => {
if ('mint' in filter) {
_args.push({mint: filter.mint.toBase58()}); _args.push({mint: filter.mint.toBase58()});
} else { } else {
_args.push({programId: filter.programId.toBase58()}); _args.push({programId: filter.programId.toBase58()});
} }
})(filter);
const args = this._argsWithCommitment(_args, commitment); const args = this._argsWithCommitment(_args, commitment);
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args); const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
@ -1489,7 +1559,7 @@ export class Connection {
return { return {
context, context,
value: value.map(result => ({ value: value.map(result => ({
pubkey: result.pubkey, pubkey: new PublicKey(result.pubkey),
account: { account: {
executable: result.account.executable, executable: result.account.executable,
owner: new PublicKey(result.account.owner), owner: new PublicKey(result.account.owner),
@ -1500,6 +1570,57 @@ export class Connection {
}; };
} }
/**
* Fetch parsed token accounts owned by the specified account
*
* @return {Promise<RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo<ParsedAccountData>}>>>}
*/
async getParsedTokenAccountsByOwner(
ownerAddress: PublicKey,
filter: TokenAccountsFilter,
commitment: ?Commitment,
): Promise<
RpcResponseAndContext<
Array<{pubkey: PublicKey, account: AccountInfo<ParsedAccountData>}>,
>,
> {
let _args = [ownerAddress.toBase58()];
if (filter.mint) {
_args.push({mint: filter.mint.toBase58()});
} else {
_args.push({programId: filter.programId.toBase58()});
}
const args = this._argsWithCommitment(_args, commitment, 'jsonParsed');
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
const res = GetParsedTokenAccountsByOwner(unsafeRes);
if (res.error) {
throw new Error(
'failed to get token accounts owned by account ' +
ownerAddress.toBase58() +
': ' +
res.error.message,
);
}
const {result} = res;
const {context, value} = result;
assert(typeof result !== 'undefined');
return {
context,
value: value.map(result => ({
pubkey: new PublicKey(result.pubkey),
account: {
executable: result.account.executable,
owner: new PublicKey(result.account.owner),
lamports: result.account.lamports,
data: result.account.data,
},
})),
};
}
/** /**
* Fetch the 20 largest accounts with their current balances * Fetch the 20 largest accounts with their current balances
*/ */
@ -1530,7 +1651,7 @@ export class Connection {
async getAccountInfoAndContext( async getAccountInfoAndContext(
publicKey: PublicKey, publicKey: PublicKey,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<RpcResponseAndContext<AccountInfo | null>> { ): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>> {
const args = this._argsWithCommitment([publicKey.toBase58()], commitment); const args = this._argsWithCommitment([publicKey.toBase58()], commitment);
const unsafeRes = await this._rpcRequest('getAccountInfo', args); const unsafeRes = await this._rpcRequest('getAccountInfo', args);
const res = GetAccountInfoAndContextRpcResult(unsafeRes); const res = GetAccountInfoAndContextRpcResult(unsafeRes);
@ -1563,13 +1684,64 @@ export class Connection {
}; };
} }
/**
* Fetch parsed account info for the specified public key
*/
async getParsedAccountInfo(
publicKey: PublicKey,
commitment: ?Commitment,
): Promise<
RpcResponseAndContext<AccountInfo<Buffer | ParsedAccountData> | null>,
> {
const args = this._argsWithCommitment(
[publicKey.toBase58()],
commitment,
'jsonParsed',
);
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
const res = GetParsedAccountInfoResult(unsafeRes);
if (res.error) {
throw new Error(
'failed to get info about account ' +
publicKey.toBase58() +
': ' +
res.error.message,
);
}
assert(typeof res.result !== 'undefined');
let value = null;
if (res.result.value) {
const {executable, owner, lamports, data: resultData} = res.result.value;
let data = resultData;
if (!data.program) {
data = bs58.decode(data);
}
value = {
executable,
owner: new PublicKey(owner),
lamports,
data,
};
}
return {
context: {
slot: res.result.context.slot,
},
value,
};
}
/** /**
* Fetch all the account info for the specified public key * Fetch all the account info for the specified public key
*/ */
async getAccountInfo( async getAccountInfo(
publicKey: PublicKey, publicKey: PublicKey,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<AccountInfo | null> { ): Promise<AccountInfo<Buffer> | null> {
return await this.getAccountInfoAndContext(publicKey, commitment) return await this.getAccountInfoAndContext(publicKey, commitment)
.then(x => x.value) .then(x => x.value)
.catch(e => { .catch(e => {
@ -1582,12 +1754,12 @@ export class Connection {
/** /**
* Fetch all the accounts owned by the specified program id * Fetch all the accounts owned by the specified program id
* *
* @return {Promise<Array<{pubkey: PublicKey, account: AccountInfo}>>} * @return {Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>>}
*/ */
async getProgramAccounts( async getProgramAccounts(
programId: PublicKey, programId: PublicKey,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<Array<{pubkey: PublicKey, account: AccountInfo}>> { ): Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>> {
const args = this._argsWithCommitment([programId.toBase58()], commitment); const args = this._argsWithCommitment([programId.toBase58()], commitment);
const unsafeRes = await this._rpcRequest('getProgramAccounts', args); const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
const res = GetProgramAccountsRpcResult(unsafeRes); const res = GetProgramAccountsRpcResult(unsafeRes);
@ -1605,7 +1777,7 @@ export class Connection {
return result.map(result => { return result.map(result => {
return { return {
pubkey: result.pubkey, pubkey: new PublicKey(result.pubkey),
account: { account: {
executable: result.account.executable, executable: result.account.executable,
owner: new PublicKey(result.account.owner), owner: new PublicKey(result.account.owner),
@ -1616,6 +1788,59 @@ export class Connection {
}); });
} }
/**
* Fetch and parse all the accounts owned by the specified program id
*
* @return {Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer | ParsedAccountData>}>>}
*/
async getParsedProgramAccounts(
programId: PublicKey,
commitment: ?Commitment,
): Promise<
Array<{
pubkey: PublicKey,
account: AccountInfo<Buffer | ParsedAccountData>,
}>,
> {
const args = this._argsWithCommitment(
[programId.toBase58()],
commitment,
'jsonParsed',
);
const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
const res = GetParsedProgramAccountsRpcResult(unsafeRes);
if (res.error) {
throw new Error(
'failed to get accounts owned by program ' +
programId.toBase58() +
': ' +
res.error.message,
);
}
const {result} = res;
assert(typeof result !== 'undefined');
return result.map(result => {
const resultData = result.account.data;
let data = resultData;
if (!data.program) {
data = bs58.decode(data);
}
return {
pubkey: new PublicKey(result.pubkey),
account: {
executable: result.account.executable,
owner: new PublicKey(result.account.owner),
lamports: result.account.lamports,
data,
},
};
});
}
/** /**
* Confirm the transaction identified by the specified signature * Confirm the transaction identified by the specified signature
*/ */
@ -2625,10 +2850,21 @@ export class Connection {
} }
} }
_argsWithCommitment(args: Array<any>, override: ?Commitment): Array<any> { _argsWithCommitment(
args: Array<any>,
override: ?Commitment,
encoding?: 'jsonParsed',
): Array<any> {
const commitment = override || this._commitment; const commitment = override || this._commitment;
if (commitment || encoding) {
let options: any = {};
if (encoding) {
options.encoding = encoding;
}
if (commitment) { if (commitment) {
args.push({commitment}); options.commitment = commitment;
}
args.push(options);
} }
return args; return args;
} }

View File

@ -77,6 +77,12 @@ test('get account info - not found', async () => {
]); ]);
expect(await connection.getAccountInfo(account.publicKey)).toBeNull(); expect(await connection.getAccountInfo(account.publicKey)).toBeNull();
if (!mockRpcEnabled) {
expect(
(await connection.getParsedAccountInfo(account.publicKey)).value,
).toBeNull();
}
}); });
test('get program accounts', async () => { test('get program accounts', async () => {
@ -282,20 +288,39 @@ test('get program accounts', async () => {
expect(programAccounts.length).toBe(2); expect(programAccounts.length).toBe(2);
programAccounts.forEach(function (element) { programAccounts.forEach(function (element) {
expect([ if (element.pubkey.equals(account0.publicKey)) {
account0.publicKey.toBase58(),
account1.publicKey.toBase58(),
]).toEqual(expect.arrayContaining([element.pubkey]));
if (element.pubkey == account0.publicKey) {
expect(element.account.lamports).toBe( expect(element.account.lamports).toBe(
LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature,
); );
} else { } else if (element.pubkey.equals(account1.publicKey)) {
expect(element.account.lamports).toBe( expect(element.account.lamports).toBe(
0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature,
); );
} else {
expect(element.pubkey.equals(account1.publicKey)).toBe(true);
} }
}); });
if (!mockRpcEnabled) {
const programAccounts = await connection.getParsedProgramAccounts(
programId.publicKey,
);
expect(programAccounts.length).toBe(2);
programAccounts.forEach(function (element) {
if (element.pubkey.equals(account0.publicKey)) {
expect(element.account.lamports).toBe(
LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature,
);
} else if (element.pubkey.equals(account1.publicKey)) {
expect(element.account.lamports).toBe(
0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature,
);
} else {
expect(element.pubkey.equals(account1.publicKey)).toBe(true);
}
});
}
}); });
test('validatorExit', async () => { test('validatorExit', async () => {
@ -1410,6 +1435,55 @@ describe('token methods', () => {
).rejects.toThrow(); ).rejects.toThrow();
}); });
test('get parsed token account info', async () => {
const accountInfo = (
await connection.getParsedAccountInfo(testTokenAccount)
).value;
if (accountInfo) {
const data = accountInfo.data;
if (data instanceof Buffer) {
expect(data instanceof Buffer).toBe(false);
} else {
expect(data.program).toEqual('spl-token');
expect(data.parsed).toBeTruthy();
}
}
});
test('get parsed token program accounts', async () => {
const tokenAccounts = await connection.getParsedProgramAccounts(
TOKEN_PROGRAM_ID,
);
tokenAccounts.forEach(({account}) => {
expect(account.owner.equals(TOKEN_PROGRAM_ID)).toBe(true);
const data = account.data;
if (data instanceof Buffer) {
expect(data instanceof Buffer).toBe(false);
} else {
expect(data.parsed).toBeTruthy();
expect(data.program).toEqual('spl-token');
}
});
});
test('get parsed token accounts by owner', async () => {
const tokenAccounts = (
await connection.getParsedTokenAccountsByOwner(testOwner.publicKey, {
mint: testToken.publicKey,
})
).value;
tokenAccounts.forEach(({account}) => {
expect(account.owner.equals(TOKEN_PROGRAM_ID)).toBe(true);
const data = account.data;
if (data instanceof Buffer) {
expect(data instanceof Buffer).toBe(false);
} else {
expect(data.parsed).toBeTruthy();
expect(data.program).toEqual('spl-token');
}
});
});
test('get token accounts by owner', async () => { test('get token accounts by owner', async () => {
const accountsWithMintFilter = ( const accountsWithMintFilter = (
await connection.getTokenAccountsByOwner(testOwner.publicKey, { await connection.getTokenAccountsByOwner(testOwner.publicKey, {
@ -1611,6 +1685,45 @@ test('request airdrop', async () => {
expect(accountInfo.lamports).toBe(minimumAmount + 42); expect(accountInfo.lamports).toBe(minimumAmount + 42);
expect(accountInfo.data).toHaveLength(0); expect(accountInfo.data).toHaveLength(0);
expect(accountInfo.owner).toEqual(SystemProgram.programId); expect(accountInfo.owner).toEqual(SystemProgram.programId);
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [
account.publicKey.toBase58(),
{commitment: 'recent', encoding: 'jsonParsed'},
],
},
{
error: null,
result: {
context: {
slot: 11,
},
value: {
owner: '11111111111111111111111111111111',
lamports: minimumAmount + 42,
data: '',
executable: false,
},
},
},
]);
const parsedAccountInfo = (
await connection.getParsedAccountInfo(account.publicKey)
).value;
if (parsedAccountInfo === null) {
expect(parsedAccountInfo).not.toBeNull();
return;
} else if (parsedAccountInfo.data.parsed) {
expect(parsedAccountInfo.data.parsed).not.toBeTruthy();
return;
}
expect(parsedAccountInfo.lamports).toBe(minimumAmount + 42);
expect(parsedAccountInfo.data).toHaveLength(0);
expect(parsedAccountInfo.owner).toEqual(SystemProgram.programId);
}); });
test('transaction failure', async () => { test('transaction failure', async () => {