feat: add parsed account data APIs
This commit is contained in:
		
				
					committed by
					
						
						Justin Starry
					
				
			
			
				
	
			
			
			
						parent
						
							b36e60738e
						
					
				
				
					commit
					c7a2fbe7eb
				
			
							
								
								
									
										1
									
								
								web3.js/flow-typed/superstruct.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								web3.js/flow-typed/superstruct.js
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,7 @@
 | 
			
		||||
declare module 'superstruct' {
 | 
			
		||||
  declare type StructFunc = {
 | 
			
		||||
      (any): any,
 | 
			
		||||
      object(schema: any): any;
 | 
			
		||||
      union(schema: any): any;
 | 
			
		||||
      array(schema: any): any;
 | 
			
		||||
      literal(schema: any): any;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								web3.js/module.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								web3.js/module.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -104,16 +104,16 @@ declare module '@solana/web3.js' {
 | 
			
		||||
    feeCalculator: FeeCalculator;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  export type PublicKeyAndAccount = {
 | 
			
		||||
  export type PublicKeyAndAccount<T> = {
 | 
			
		||||
    pubkey: PublicKey;
 | 
			
		||||
    account: AccountInfo;
 | 
			
		||||
    account: AccountInfo<T>;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  export type AccountInfo = {
 | 
			
		||||
  export type AccountInfo<T> = {
 | 
			
		||||
    executable: boolean;
 | 
			
		||||
    owner: PublicKey;
 | 
			
		||||
    lamports: number;
 | 
			
		||||
    data: Buffer;
 | 
			
		||||
    data: T;
 | 
			
		||||
    rentEpoch?: number;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@@ -181,9 +181,14 @@ declare module '@solana/web3.js' {
 | 
			
		||||
    meta: ConfirmedTransactionMeta | null;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  export type ParsedAccountData = {
 | 
			
		||||
    program: string;
 | 
			
		||||
    parsed: any;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  export type KeyedAccountInfo = {
 | 
			
		||||
    accountId: PublicKey;
 | 
			
		||||
    accountInfo: AccountInfo;
 | 
			
		||||
    accountInfo: AccountInfo<Buffer>;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  export type Version = {
 | 
			
		||||
@@ -210,7 +215,7 @@ declare module '@solana/web3.js' {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  export type AccountChangeCallback = (
 | 
			
		||||
    accountInfo: AccountInfo,
 | 
			
		||||
    accountInfo: AccountInfo<Buffer>,
 | 
			
		||||
    context: Context,
 | 
			
		||||
  ) => void;
 | 
			
		||||
  export type ProgramAccountChangeCallback = (
 | 
			
		||||
@@ -280,15 +285,25 @@ declare module '@solana/web3.js' {
 | 
			
		||||
    getAccountInfoAndContext(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment?: Commitment,
 | 
			
		||||
    ): Promise<RpcResponseAndContext<AccountInfo | null>>;
 | 
			
		||||
    ): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>>;
 | 
			
		||||
    getAccountInfo(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment?: Commitment,
 | 
			
		||||
    ): Promise<AccountInfo | null>;
 | 
			
		||||
    ): Promise<AccountInfo<Buffer> | null>;
 | 
			
		||||
    getParsedAccountInfo(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment?: Commitment,
 | 
			
		||||
    ): Promise<
 | 
			
		||||
      RpcResponseAndContext<AccountInfo<Buffer | ParsedAccountData> | null>
 | 
			
		||||
    >;
 | 
			
		||||
    getProgramAccounts(
 | 
			
		||||
      programId: PublicKey,
 | 
			
		||||
      commitment?: Commitment,
 | 
			
		||||
    ): Promise<Array<PublicKeyAndAccount>>;
 | 
			
		||||
    ): Promise<Array<PublicKeyAndAccount<Buffer>>>;
 | 
			
		||||
    getParsedProgramAccounts(
 | 
			
		||||
      programId: PublicKey,
 | 
			
		||||
      commitment?: Commitment,
 | 
			
		||||
    ): Promise<Array<PublicKeyAndAccount<Buffer | ParsedAccountData>>>;
 | 
			
		||||
    getBalanceAndContext(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment?: Commitment,
 | 
			
		||||
@@ -311,7 +326,18 @@ declare module '@solana/web3.js' {
 | 
			
		||||
      filter: TokenAccountsFilter,
 | 
			
		||||
      commitment?: Commitment,
 | 
			
		||||
    ): 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(
 | 
			
		||||
      config?: GetLargestAccountsConfig,
 | 
			
		||||
 
 | 
			
		||||
@@ -125,16 +125,16 @@ declare module '@solana/web3.js' {
 | 
			
		||||
    feeCalculator: FeeCalculator,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  declare export type PublicKeyAndAccount = {
 | 
			
		||||
  declare export type PublicKeyAndAccount<T> = {
 | 
			
		||||
    pubkey: PublicKey,
 | 
			
		||||
    account: AccountInfo,
 | 
			
		||||
    account: AccountInfo<T>,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  declare export type AccountInfo = {
 | 
			
		||||
  declare export type AccountInfo<T> = {
 | 
			
		||||
    executable: boolean,
 | 
			
		||||
    owner: PublicKey,
 | 
			
		||||
    lamports: number,
 | 
			
		||||
    data: Buffer,
 | 
			
		||||
    data: T,
 | 
			
		||||
    rentEpoch: number | null,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@@ -169,6 +169,11 @@ declare module '@solana/web3.js' {
 | 
			
		||||
    meta: ConfirmedTransactionMeta | null,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  declare export type ParsedAccountData = {
 | 
			
		||||
    program: string,
 | 
			
		||||
    parsed: any,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  declare export type ParsedMessageAccount = {
 | 
			
		||||
    pubkey: PublicKey,
 | 
			
		||||
    signer: boolean,
 | 
			
		||||
@@ -204,7 +209,7 @@ declare module '@solana/web3.js' {
 | 
			
		||||
 | 
			
		||||
  declare export type KeyedAccountInfo = {
 | 
			
		||||
    accountId: PublicKey,
 | 
			
		||||
    accountInfo: AccountInfo,
 | 
			
		||||
    accountInfo: AccountInfo<Buffer>,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  declare export type Version = {
 | 
			
		||||
@@ -231,7 +236,7 @@ declare module '@solana/web3.js' {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  declare type AccountChangeCallback = (
 | 
			
		||||
    accountInfo: AccountInfo,
 | 
			
		||||
    accountInfo: AccountInfo<Buffer>,
 | 
			
		||||
    context: Context,
 | 
			
		||||
  ) => void;
 | 
			
		||||
  declare type ProgramAccountChangeCallback = (
 | 
			
		||||
@@ -301,15 +306,25 @@ declare module '@solana/web3.js' {
 | 
			
		||||
    getAccountInfoAndContext(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment: ?Commitment,
 | 
			
		||||
    ): Promise<RpcResponseAndContext<AccountInfo | null>>;
 | 
			
		||||
    ): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>>;
 | 
			
		||||
    getAccountInfo(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment: ?Commitment,
 | 
			
		||||
    ): Promise<AccountInfo | null>;
 | 
			
		||||
    ): Promise<AccountInfo<Buffer> | null>;
 | 
			
		||||
    getParsedAccountInfo(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment: ?Commitment,
 | 
			
		||||
    ): Promise<
 | 
			
		||||
      RpcResponseAndContext<AccountInfo<Buffer | ParsedAccountData> | null>,
 | 
			
		||||
    >;
 | 
			
		||||
    getProgramAccounts(
 | 
			
		||||
      programId: PublicKey,
 | 
			
		||||
      commitment: ?Commitment,
 | 
			
		||||
    ): Promise<Array<PublicKeyAndAccount>>;
 | 
			
		||||
    ): Promise<Array<PublicKeyAndAccount<Buffer>>>;
 | 
			
		||||
    getParsedProgramAccounts(
 | 
			
		||||
      programId: PublicKey,
 | 
			
		||||
      commitment: ?Commitment,
 | 
			
		||||
    ): Promise<Array<PublicKeyAndAccount<Buffer | ParsedAccountData>>>;
 | 
			
		||||
    getBalanceAndContext(
 | 
			
		||||
      publicKey: PublicKey,
 | 
			
		||||
      commitment: ?Commitment,
 | 
			
		||||
@@ -332,7 +347,9 @@ declare module '@solana/web3.js' {
 | 
			
		||||
      filter: TokenAccountsFilter,
 | 
			
		||||
      commitment: ?Commitment,
 | 
			
		||||
    ): Promise<
 | 
			
		||||
      RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo}>>,
 | 
			
		||||
      RpcResponseAndContext<
 | 
			
		||||
        Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>,
 | 
			
		||||
      >,
 | 
			
		||||
    >;
 | 
			
		||||
    getLargestAccounts(
 | 
			
		||||
      config: ?GetLargestAccountsConfig,
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,12 @@ export const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
 | 
			
		||||
type RpcRequest = (methodName: string, args: Array<any>) => any;
 | 
			
		||||
 | 
			
		||||
type TokenAccountsFilter =
 | 
			
		||||
  | {
 | 
			
		||||
  | {|
 | 
			
		||||
      mint: PublicKey,
 | 
			
		||||
    }
 | 
			
		||||
  | {
 | 
			
		||||
    |}
 | 
			
		||||
  | {|
 | 
			
		||||
      programId: PublicKey,
 | 
			
		||||
    };
 | 
			
		||||
    |};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Extra contextual information for RPC responses
 | 
			
		||||
@@ -634,13 +634,34 @@ const GetTokenSupplyRpcResult = jsonRpcResultAndContext(TokenAmountResult);
 | 
			
		||||
 */
 | 
			
		||||
const GetTokenAccountsByOwner = jsonRpcResultAndContext(
 | 
			
		||||
  struct.array([
 | 
			
		||||
    struct({
 | 
			
		||||
    struct.object({
 | 
			
		||||
      pubkey: 'string',
 | 
			
		||||
      account: struct({
 | 
			
		||||
      account: struct.object({
 | 
			
		||||
        executable: 'boolean',
 | 
			
		||||
        owner: 'string',
 | 
			
		||||
        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?',
 | 
			
		||||
      }),
 | 
			
		||||
    }),
 | 
			
		||||
@@ -692,6 +713,23 @@ const AccountInfoResult = struct({
 | 
			
		||||
  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
 | 
			
		||||
 */
 | 
			
		||||
@@ -699,6 +737,13 @@ const GetAccountInfoAndContextRpcResult = jsonRpcResultAndContext(
 | 
			
		||||
  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
 | 
			
		||||
 */
 | 
			
		||||
@@ -737,6 +782,14 @@ const ProgramAccountInfoResult = struct({
 | 
			
		||||
  account: AccountInfoResult,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
const ParsedProgramAccountInfoResult = struct({
 | 
			
		||||
  pubkey: 'string',
 | 
			
		||||
  account: ParsedAccountInfoResult,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
 * Expected JSON RPC response for the "programNotification" message
 | 
			
		||||
 */
 | 
			
		||||
@@ -785,6 +838,13 @@ const GetProgramAccountsRpcResult = jsonRpcResult(
 | 
			
		||||
  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
 | 
			
		||||
 */
 | 
			
		||||
@@ -1051,20 +1111,32 @@ type SlotInfo = {
 | 
			
		||||
  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
 | 
			
		||||
 *
 | 
			
		||||
 * @typedef {Object} AccountInfo
 | 
			
		||||
 * @property {number} lamports Number of lamports assigned to 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
 | 
			
		||||
 */
 | 
			
		||||
type AccountInfo = {
 | 
			
		||||
type AccountInfo<T> = {
 | 
			
		||||
  executable: boolean,
 | 
			
		||||
  owner: PublicKey,
 | 
			
		||||
  lamports: number,
 | 
			
		||||
  data: Buffer,
 | 
			
		||||
  data: T,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1072,18 +1144,18 @@ type AccountInfo = {
 | 
			
		||||
 *
 | 
			
		||||
 * @typedef {Object} KeyedAccountInfo
 | 
			
		||||
 * @property {PublicKey} accountId
 | 
			
		||||
 * @property {AccountInfo} accountInfo
 | 
			
		||||
 * @property {AccountInfo<Buffer>} accountInfo
 | 
			
		||||
 */
 | 
			
		||||
type KeyedAccountInfo = {
 | 
			
		||||
  accountId: PublicKey,
 | 
			
		||||
  accountInfo: AccountInfo,
 | 
			
		||||
  accountInfo: AccountInfo<Buffer>,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Callback function for account change notifications
 | 
			
		||||
 */
 | 
			
		||||
export type AccountChangeCallback = (
 | 
			
		||||
  accountInfo: AccountInfo,
 | 
			
		||||
  accountInfo: AccountInfo<Buffer>,
 | 
			
		||||
  context: Context,
 | 
			
		||||
) => void;
 | 
			
		||||
 | 
			
		||||
@@ -1450,25 +1522,23 @@ export class Connection {
 | 
			
		||||
  /**
 | 
			
		||||
   * 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(
 | 
			
		||||
    ownerAddress: PublicKey,
 | 
			
		||||
    filter: TokenAccountsFilter,
 | 
			
		||||
    commitment: ?Commitment,
 | 
			
		||||
  ): Promise<
 | 
			
		||||
    RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo}>>,
 | 
			
		||||
    RpcResponseAndContext<
 | 
			
		||||
      Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>,
 | 
			
		||||
    >,
 | 
			
		||||
  > {
 | 
			
		||||
    let _args = [ownerAddress.toBase58()];
 | 
			
		||||
 | 
			
		||||
    // Strip flow types to make flow happy
 | 
			
		||||
    ((filter: any) => {
 | 
			
		||||
      if ('mint' in filter) {
 | 
			
		||||
        _args.push({mint: filter.mint.toBase58()});
 | 
			
		||||
      } else {
 | 
			
		||||
        _args.push({programId: filter.programId.toBase58()});
 | 
			
		||||
      }
 | 
			
		||||
    })(filter);
 | 
			
		||||
    if (filter.mint) {
 | 
			
		||||
      _args.push({mint: filter.mint.toBase58()});
 | 
			
		||||
    } else {
 | 
			
		||||
      _args.push({programId: filter.programId.toBase58()});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const args = this._argsWithCommitment(_args, commitment);
 | 
			
		||||
    const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
 | 
			
		||||
@@ -1489,7 +1559,7 @@ export class Connection {
 | 
			
		||||
    return {
 | 
			
		||||
      context,
 | 
			
		||||
      value: value.map(result => ({
 | 
			
		||||
        pubkey: result.pubkey,
 | 
			
		||||
        pubkey: new PublicKey(result.pubkey),
 | 
			
		||||
        account: {
 | 
			
		||||
          executable: result.account.executable,
 | 
			
		||||
          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
 | 
			
		||||
   */
 | 
			
		||||
@@ -1530,7 +1651,7 @@ export class Connection {
 | 
			
		||||
  async getAccountInfoAndContext(
 | 
			
		||||
    publicKey: PublicKey,
 | 
			
		||||
    commitment: ?Commitment,
 | 
			
		||||
  ): Promise<RpcResponseAndContext<AccountInfo | null>> {
 | 
			
		||||
  ): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>> {
 | 
			
		||||
    const args = this._argsWithCommitment([publicKey.toBase58()], commitment);
 | 
			
		||||
    const unsafeRes = await this._rpcRequest('getAccountInfo', args);
 | 
			
		||||
    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
 | 
			
		||||
   */
 | 
			
		||||
  async getAccountInfo(
 | 
			
		||||
    publicKey: PublicKey,
 | 
			
		||||
    commitment: ?Commitment,
 | 
			
		||||
  ): Promise<AccountInfo | null> {
 | 
			
		||||
  ): Promise<AccountInfo<Buffer> | null> {
 | 
			
		||||
    return await this.getAccountInfoAndContext(publicKey, commitment)
 | 
			
		||||
      .then(x => x.value)
 | 
			
		||||
      .catch(e => {
 | 
			
		||||
@@ -1582,12 +1754,12 @@ export class Connection {
 | 
			
		||||
  /**
 | 
			
		||||
   * 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(
 | 
			
		||||
    programId: PublicKey,
 | 
			
		||||
    commitment: ?Commitment,
 | 
			
		||||
  ): Promise<Array<{pubkey: PublicKey, account: AccountInfo}>> {
 | 
			
		||||
  ): Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>> {
 | 
			
		||||
    const args = this._argsWithCommitment([programId.toBase58()], commitment);
 | 
			
		||||
    const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
 | 
			
		||||
    const res = GetProgramAccountsRpcResult(unsafeRes);
 | 
			
		||||
@@ -1605,7 +1777,7 @@ export class Connection {
 | 
			
		||||
 | 
			
		||||
    return result.map(result => {
 | 
			
		||||
      return {
 | 
			
		||||
        pubkey: result.pubkey,
 | 
			
		||||
        pubkey: new PublicKey(result.pubkey),
 | 
			
		||||
        account: {
 | 
			
		||||
          executable: result.account.executable,
 | 
			
		||||
          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
 | 
			
		||||
   */
 | 
			
		||||
@@ -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;
 | 
			
		||||
    if (commitment) {
 | 
			
		||||
      args.push({commitment});
 | 
			
		||||
    if (commitment || encoding) {
 | 
			
		||||
      let options: any = {};
 | 
			
		||||
      if (encoding) {
 | 
			
		||||
        options.encoding = encoding;
 | 
			
		||||
      }
 | 
			
		||||
      if (commitment) {
 | 
			
		||||
        options.commitment = commitment;
 | 
			
		||||
      }
 | 
			
		||||
      args.push(options);
 | 
			
		||||
    }
 | 
			
		||||
    return args;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -77,6 +77,12 @@ test('get account info - not found', async () => {
 | 
			
		||||
  ]);
 | 
			
		||||
 | 
			
		||||
  expect(await connection.getAccountInfo(account.publicKey)).toBeNull();
 | 
			
		||||
 | 
			
		||||
  if (!mockRpcEnabled) {
 | 
			
		||||
    expect(
 | 
			
		||||
      (await connection.getParsedAccountInfo(account.publicKey)).value,
 | 
			
		||||
    ).toBeNull();
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('get program accounts', async () => {
 | 
			
		||||
@@ -282,20 +288,39 @@ test('get program accounts', async () => {
 | 
			
		||||
  expect(programAccounts.length).toBe(2);
 | 
			
		||||
 | 
			
		||||
  programAccounts.forEach(function (element) {
 | 
			
		||||
    expect([
 | 
			
		||||
      account0.publicKey.toBase58(),
 | 
			
		||||
      account1.publicKey.toBase58(),
 | 
			
		||||
    ]).toEqual(expect.arrayContaining([element.pubkey]));
 | 
			
		||||
    if (element.pubkey == account0.publicKey) {
 | 
			
		||||
    if (element.pubkey.equals(account0.publicKey)) {
 | 
			
		||||
      expect(element.account.lamports).toBe(
 | 
			
		||||
        LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature,
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
    } 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);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  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 () => {
 | 
			
		||||
@@ -1410,6 +1435,55 @@ describe('token methods', () => {
 | 
			
		||||
    ).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 () => {
 | 
			
		||||
    const accountsWithMintFilter = (
 | 
			
		||||
      await connection.getTokenAccountsByOwner(testOwner.publicKey, {
 | 
			
		||||
@@ -1611,6 +1685,45 @@ test('request airdrop', async () => {
 | 
			
		||||
  expect(accountInfo.lamports).toBe(minimumAmount + 42);
 | 
			
		||||
  expect(accountInfo.data).toHaveLength(0);
 | 
			
		||||
  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 () => {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user