Interacting with Wallets

API

Wallets

A wallet allows you to store, receive, and send cryptocurrency. It contains one or more public addresses and private keys, which are used to interact with the blockchain. A private key is used to access and control funds stored in a public address. Some wallets also include additional features such as exchange functionality, backup and recovery options, and multi-sig support. It is important to securely store private keys and to use a reputable wallet provider.

There are multiple software wallets, but for this course we are using the Phantom Wallet.

Keypairs

Wallets heavily rely on Keypairs, which was covered in Assignment 2

Wallet Adapters

A wallet adapter is a software component that facilitates communication between a cryptocurrency wallet and a blockchain network. It acts as an interface between the two, converting the data format and protocols used by the wallet to those required by the blockchain and vice versa. This enables the wallet to securely interact with the blockchain, allowing users to store, send and receive cryptocurrency.

For example, in the context of a web wallet, the adapter would handle the connection to the blockchain, processing of transactions, and storage of private keys.

The Solana Wallet Adapter:

  • Comprises multiple modular packages, including @solana/wallet-adapter-base, @solana/wallet-adapter-react, and packages for specific wallets like @solana/wallet-adapter-phantom.

  • Contains packages for UI components, such as @solana/wallet-adapter-react-ui

Connecting to Wallets

Package Installations

npm install @solana/wallet-adapter-base \\
    @solana/wallet-adapter-react \\
    @solana/wallet-adapter-phantom \\
    @solana/wallet-adapter-react-ui

Sample Connection

import { NextPage } from 'next'
import { FC, ReactNode } from "react"
import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react'
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom'
import * as web3 from '@solana/web3.js'

// Component that renders the app 
export const Home: NextPage = (props) => {
    // URL for Solana devnet cluster
    const endpoint = web3.clusterApiUrl('devnet')
    // Use PhantomWalletAdapter to handle wallet functionality
    const wallet = new PhantomWalletAdapter()

    return (
				/* This section connects to the network and interacts with wallets */
        <ConnectionProvider endpoint={endpoint}>
            <WalletProvider wallets={[wallet]}>
                <p>Filler Code</p>
            </WalletProvider>
        </ConnectionProvider>
    )
}

Assignment

  1. Create a new React component that displays the balance and a list of transactions of a Solana account.

  2. Use the @solana/web3.js API to query the balance and transactions of the account.

  3. Use the PhantomWalletAdapter to get the public address of the user's wallet.

  4. Display the balance, public address, and a list of transactions (sorted by date) on the component.

  5. Add a button that allows the user to refresh the transaction list.

  6. Use the component in the Home component as a child of the WalletProvider.

Deliverables:

  • The updated Home component that displays the balance, public address, and a list of transactions of the user's Solana account.

  • A brief explanation of how you queried the balance and transactions and used the PhantomWalletAdapter to get the public address.

Hint 1
Solution and Explanation
import React, { useState, useEffect } from 'react';
import { Keypair, Client, SolanaTransaction } from '@solana/web3.js';
import PhantomWalletAdapter from '@solana/phantom-wallet-adapter';

function AccountInfo() {
  const [balance, setBalance] = useState(0);
  const [address, setAddress] = useState('');
  const [transactions, setTransactions] = useState([]);

  useEffect(() => {
    const getInfo = async () => {
      const wallet = await PhantomWalletAdapter.getInstance();
      const publicKey = wallet.publicKey;
      setAddress(publicKey);
      const client = new Client();
      const accountInfo = await client.getAccountInfo(publicKey);
      setBalance(accountInfo.lamports / 1e6);
      const recentTransactions = await client.getRecentBlockhash(publicKey);
      const txs = await Promise.all(
        recentTransactions.map(async (tx) => {
          const transaction = await client.getTransaction(tx);
          return {
            date: transaction.timestamp,
            amount: transaction.amount / 1e6,
            recipient: transaction.toPublicKey,
          };
        })
      );
      setTransactions(txs.sort((a, b) => b.date - a.date));
    };
    getInfo();
  }, []);

  return (
    <div>
      <p>Public Address: {address}</p>
      <p>Balance: {balance} SOL</p>
      <h2>Recent Transactions</h2>
      <ul>
        {transactions.map((tx, index) => (
          <li key={index}>
            Date: {new Date(tx.date * 1000).toString()} | Amount: {tx.amount} SOL
            | Recipient: {tx.recipient}
          </li>
        ))}
      </ul>
      <button onClick={() => window.location.reload()}>Refresh</button>
    </div>
  );
}

export default AccountInfo;

Explanation

  • This React component uses the useState and useEffect hooks to query the balance, public address, and transactions of the user's Solana account.

  • It starts by getting the instance of the PhantomWalletAdapter which returns the public key of the user's wallet.

  • Then, it creates an instance of the Client from the @solana/web3.js library to query the balance and transactions of the account using the public key.

  • The balance is converted from lamports to SOL, and the transactions are sorted by date.

  • The component displays the public address, balance, and a list of recent transactions in a list format.

  • Finally, it has a button that reloads the page to refresh the transaction list.

Once you’re done, make a PR with your react app to the homework repository on Github.

Last updated