Get Balance and all custom token list of Solana tokens in Wallet

I'm actually stuck at the first step on connecting to phantom wallet. I'm trying to perform the following step.

  1. Connect to Phantom wallet
  2. Get a Public key
  3. Get Balance of all tokens
  4. Perform Buy/Sell

I'm able to connect to a phantom wallet with the below code. I'm not sure if the next step in the process is to get a public key so that I can find the balance of all tokens as part of the account.

const balance = connection.getBalance(publicKey); The above method is what I found from the documentation, but I'm not sure how can I get the publicKey of the end user who connected their wallet to the webiste.

const connection = new solanaWeb3.Connection(solanaWeb3.clusterApiUrl("mainnet-beta")) console.log(connection);


Solution 1:

assume you have react app for integrating with solana wallets, first of all install these packages:

yarn add @solana/wallet-adapter-base \
     @solana/wallet-adapter-react \
     @solana/wallet-adapter-react-ui \
     @solana/wallet-adapter-wallets \
     @solana/web3.js \
     react

you can use next, vue, angular, svelte and material ui as well

next we have this setup:

import React, { FC, useMemo } from 'react';
import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react';
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base';
import {
    //LedgerWalletAdapter,
    PhantomWalletAdapter,
    SolflareWalletAdapter,
    //SlopeWalletAdapter,
    //SolletExtensionWalletAdapter,
    //SolletWalletAdapter,
    //TorusWalletAdapter,
} from '@solana/wallet-adapter-wallets';
import {
    WalletModalProvider,
    WalletDisconnectButton,
    WalletMultiButton
} from '@solana/wallet-adapter-react-ui';
import { clusterApiUrl } from '@solana/web3.js';

// Default styles that can be overridden by your app
require('@solana/wallet-adapter-react-ui/styles.css');

export const Wallet: FC = () => {
    // The network can be set to 'devnet', 'testnet', or 'mainnet-beta'.
    const network = WalletAdapterNetwork.Devnet;

    // You can also provide a custom RPC endpoint.
    const endpoint = useMemo(() => clusterApiUrl(network), [network]);

    // @solana/wallet-adapter-wallets includes all the adapters but supports tree shaking and lazy loading --
    // Only the wallets you configure here will be compiled into your application, and only the dependencies
    // of wallets that your users connect to will be loaded.
    const wallets = useMemo(
        () => [
            new PhantomWalletAdapter(),
            new SlopeWalletAdapter(),
            new SolflareWalletAdapter(),
            new TorusWalletAdapter(),
            new LedgerWalletAdapter(),
            new SolletWalletAdapter({ network }),
            new SolletExtensionWalletAdapter({ network }),
        ],
        [network]
    );

    return (
        <ConnectionProvider endpoint={endpoint}>
            <WalletProvider wallets={wallets} autoConnect>
                <WalletModalProvider>
                    <WalletMultiButton />
                    <WalletDisconnectButton />
                    { /* Your app's components go here, nested within the context providers. */ }
                </WalletModalProvider>
            </WalletProvider>
        </ConnectionProvider>
    );
};
  • after import modules, I commented some wallet adapters except phantom and solfare

also this code block is so important:

        <ConnectionProvider endpoint={endpoint}>
            <WalletProvider wallets={wallets} autoConnect>
                <WalletModalProvider>
                    <WalletMultiButton />
                    <WalletDisconnectButton />
                    { /* Your app's components go here, nested within the context 
                      providers. */ }
                </WalletModalProvider>
            </WalletProvider>
        </ConnectionProvider>

modals with functional buttons surrounded by

  • ConnectionProvider: prepare endpoint for wallets to connecting to and query wallet tokens
  • WalletProvider: prepare which wallets should be load in modals and ready to connect

and finally usage:

import { WalletNotConnectedError } from '@solana/wallet-adapter-base';
import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { Keypair, SystemProgram, Transaction } from '@solana/web3.js';
import React, { FC, useCallback } from 'react';

export const SendOneLamportToRandomAddress: FC = () => {
    const { connection } = useConnection();
    const { publicKey, sendTransaction } = useWallet();

    const onClick = useCallback(async () => {
        if (!publicKey) throw new WalletNotConnectedError();

        const transaction = new Transaction().add(
            SystemProgram.transfer({
                fromPubkey: publicKey,
                toPubkey: Keypair.generate().publicKey,
                lamports: 1,
            })
        );

        const signature = await sendTransaction(transaction, connection);

        await connection.confirmTransaction(signature, 'processed');
    }, [publicKey, sendTransaction, connection]);

    return (
        <button onClick={onClick} disabled={!publicKey}>
            Send 1 lamport to a random address!
        </button>
    );
};

so as you can see above this part

const { connection } = useConnection();
const { publicKey, sendTransaction } = useWallet();

was prepared for making a connection and give you connected wallet public key and also make use of sendTransaction function of connected wallet, sounds good!

other parts of code are obvous i think.

so, how many functions we have with wallet adapters like phantom? and what functions? we can get public key, connecting(boolean), connected(boolean), readyState.

also we have some other main functions like:

  • connect
  • disconnect
  • sendTransaction
  • signTransaction
  • signAllTransactions
  • signMessage

you can see all of them in this github repo link

another point is if you use Anchor framework you should know that Anchor uses its own "Wallet" object to interact with the connected wallet and sign transactions on its behalf. so In order to get an object compatible with Anchor's definition of a wallet, we can use yet another composable called useAnchorWallet. This will return a wallet object that can sign transactions.

const wallet = useAnchorWallet()

have fun