rpc – Implementing getTokenAccountsByOwner in GraphQL

I took a stab at building a graphQL query that could return all tokenAccounts and their balances owned by a given wallet address and failed. The current GraphQL implementation does not support filtering in this way, and we can’t just query for all token accounts and the filter afterwards. Is there no way to do this in GraphQL currently?

import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
import { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
import { createSolanaRpc } from '@solana/rpc';
import { createSolanaRpcGraphQL } from '@solana/rpc-graphql';

const rpc = createSolanaRpc('https://api.devnet.solana.com');
const rpcGraphQL = createSolanaRpcGraphQL(rpc);
const wallet = "[WALLET ADDRESS]";

query getTokenBalances($walletAddress: String!, $tokenProgram: String!, $token2022Program: String!) {
  # Get native SOL balance
  solAccount: account(address: $walletAddress) {
    lamports
  }
  
  # Get SPL Token accounts
  tokenAccounts: programAccounts(
    programAddress: $tokenProgram,
    filters: [
      { memcmp: { offset: 32, bytes: $walletAddress } }
    ]
  ) {
    ... on TokenAccount {
      address
      mint {
        ... on MintAccount {
          address
          decimals
          extensions {
            ... on SplTokenExtensionTokenMetadata {
              name
              symbol
              uri
            }
          }
        }
      }
      owner {
        address
      }
      tokenAmount {
        amount
        decimals
        uiAmountString
      }
    }
  }
  
  # Get Token-2022 accounts (with same filter)
  token2022Accounts: programAccounts(
    programAddress: $token2022Program,
    filters: [
      { memcmp: { offset: 32, bytes: $walletAddress } }
    ]
  ) {
    ... on TokenAccount {
      address
      mint {
        ... on MintAccount {
          address
          decimals
          extensions {
            ... on SplTokenExtensionTokenMetadata {
              name
              symbol
              uri
            }
          }
        }
      }
      owner {
        address
      }
      tokenAmount {
        amount
        decimals
        uiAmountString
      }
    }
  }
}

const graphqlResult = await rpcGraphQL.query(getTokenAccountsQuery, {
      walletAddress: address(wallet.address),
      tokenProgram: address(TOKEN_PROGRAM_ADDRESS),
      token2022Program: address(TOKEN_2022_PROGRAM_ADDRESS)
});

console.log('GraphQL result:', graphqlResult);

The result of the above console log is: GraphQLError: Unknown argument “filters” on field “Query.programAccounts”. at Object.Argument

If you remove the filter you get, quite reasonably, SolanaError: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA excluded from account secondary indexes; this RPC method unavailable for key

I love the approach and the potential efficiency gains GraphQL is promising here, but I don’t know how to approach some pretty basic things like this.

Read more here: Source link