Interacting with Wallets in Solana dApps

·

Interacting with cryptocurrency wallets is a foundational skill for building decentralized applications (dApps) on the Solana blockchain. Whether you're creating a simple frontend interface or a complex DeFi platform, understanding how users securely connect and transact through their wallets is essential. This guide walks you through the core concepts of wallet integration, focusing on software wallets like Phantom and leveraging Solana’s Wallet-Adapter library to streamline development.


Understanding Cryptocurrency Wallets

At the heart of every blockchain interaction lies cryptography — specifically, public-private key pairs. These keys allow users to prove ownership of their accounts and sign transactions without revealing sensitive information.

While the public key can be freely shared (it acts as your wallet address), the private key must remain secret. If compromised, an attacker could drain all assets from your account and perform unauthorized actions.

A wallet is any tool or device designed to securely store your private key and facilitate transaction signing. Wallets fall into two main categories:

👉 Discover how secure wallet integrations power modern dApps

Most developers building on Solana work with software wallets, especially browser-based extensions such as Phantom. These tools make it easy for websites to request user permissions, retrieve public addresses, and prompt transaction approvals — all without ever accessing the private key.

Key Interactions Between Websites and Wallets

When a dApp connects to a wallet, it can typically perform these actions:

  1. Read the user's public key (wallet address)
  2. Submit a transaction for approval
  3. Send the signed transaction to the Solana network

The actual signing happens inside the wallet app using the private key. The website only receives confirmation once the user approves the action.

⚠️ Never ask users to input their private keys into your application. Always rely on trusted wallet providers and standard protocols.

Introducing Phantom: A Leading Solana Wallet

Phantom is one of the most widely used software wallets in the Solana ecosystem. It supports major browsers (Chrome, Brave, Firefox, Edge) and offers mobile apps for iOS and Android. Its seamless integration with dApps makes it ideal for developers aiming to deliver smooth user experiences.

While supporting multiple wallets enhances accessibility, this guide focuses on Phantom due to its popularity and developer-friendly design.


Simplifying Wallet Integration with Solana’s Wallet-Adapter

Manually handling connections across different wallets would be time-consuming and error-prone. That’s where Solana’s Wallet-Adapter comes in — a modular suite of libraries that standardizes wallet interactions.

This adapter supports all wallets compliant with the Wallet Standard, which covers nearly every major Solana wallet today.

Core Packages You’ll Use


Installing Required Dependencies

To add wallet support to a React-based dApp, install the core packages:

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

These libraries enable you to manage wallet state, display connection UIs, and interact with the blockchain using clean, reusable code.


Setting Up Wallet Context Providers

To maintain consistent wallet and network connection states across your app, wrap your components with context providers.

Start by creating a WalletContextProvider.tsx file:

import { FC, ReactNode } from "react";
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import * as web3 from "@solana/web3.js";
import { useMemo } from "react";
require("@solana/wallet-adapter-react-ui/styles.css");

const WalletContextProvider: FC<{ children: ReactNode }> = ({ children }) => {
  const endpoint = web3.clusterApiUrl("devnet");
  const wallets = useMemo(() => [], []);

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets}>
        <WalletModalProvider>
          {children}
        </WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  );
};

export default WalletContextProvider;

This setup ensures your entire app has access to:

Wrap your main app component with this provider to enable global access.


Adding a Connect Wallet Button

Instead of building custom buttons, use WalletMultiButton from @solana/wallet-adapter-react-ui. It automatically changes its label based on connection status ("Connect Wallet", "Disconnect", etc.).

Update your layout component (e.g., AppBar.tsx) like so:

import { WalletMultiButton } from "@solana/wallet-adapter-react-ui";

export const AppBar: FC = () => {
  return (
    <div>
      <h2>Wallet-Adapter Example</h2>
      <WalletMultiButton />
    </div>
  );
};

Now users can click the button to select their preferred wallet (like Phantom) and connect securely.

👉 See how top dApps implement seamless wallet onboarding


Accessing User Account Information

Once connected, retrieve the user’s public key and fetch account data using useWallet and useConnection.

Here’s an example component that displays a user’s SOL balance:

import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
import { FC, useEffect, useState } from "react";

export const BalanceDisplay: FC = () => {
  const [balance, setBalance] = useState(0);
  const { connection } = useConnection();
  const { publicKey } = useWallet();

  useEffect(() => {
    if (!connection || !publicKey) return;

    // Listen for balance changes
    const subscriptionId = connection.onAccountChange(
      publicKey,
      (updatedAccountInfo) => {
        setBalance(updatedAccountInfo.lamports / LAMPORTS_PER_SOL);
      },
      "confirmed"
    );

    // Fetch initial balance
    connection.getAccountInfo(publicKey).then((info) => {
      if (info) setBalance(info.lamports / LAMPORTS_PER_SOL);
    });

    return () => {
      connection.removeAccountChangeListener(subscriptionId);
    };
  }, [connection, publicKey]);

  return <p>{publicKey ? `Balance: ${balance.toFixed(2)} SOL` : ""}</p>;
};

This component updates in real time whenever the account balance changes — perfect for dashboards or trading interfaces.


Sending Transactions via Wallet Approval

To initiate a transaction (e.g., sending tokens or interacting with a smart contract), use the sendTransaction function provided by useWallet.

Example: Sending 0.1 SOL to another address:

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

const sendSol = async (recipient: string) => {
  if (!publicKey || !connection) return;

  const transaction = new web3.Transaction();
  const recipientPubKey = new web3.PublicKey(recipient);

  const instruction = web3.SystemProgram.transfer({
    fromPubkey: publicKey,
    toPubkey: recipientPubKey,
    lamports: LAMPORTS_PER_SOL * 0.1,
  });

  transaction.add(instruction);
  try {
    const signature = await sendTransaction(transaction, connection);
    console.log("Transaction sent:", signature);
    // Optionally link to https://explorer.solana.com/tx/${signature}
  } catch (err) {
    console.error("Transaction failed:", err);
  }
};

When called, this triggers the connected wallet (e.g., Phantom) to show a confirmation popup. The user reviews and approves — or rejects — the transaction.


Frequently Asked Questions

What is a blockchain wallet?

A blockchain wallet stores cryptographic keys and enables secure interactions with decentralized networks. It allows users to view balances, receive funds, and approve transactions without exposing private keys.

Can I build a dApp without supporting Phantom?

Yes, but Phantom dominates the Solana ecosystem. Supporting it ensures broader user adoption. However, Wallet-Adapter makes adding support for other wallets straightforward.

How does Wallet-Adapter improve security?

It abstracts direct wallet communication through standardized interfaces. Your app never handles private keys — signing occurs within the isolated environment of the wallet app itself.

Why use Devnet during development?

Devnet is a public test network where developers can test applications using free SOL. It mimics mainnet behavior without financial risk.

Is it safe to connect my wallet to any site?

Only connect to trusted dApps. Malicious sites may request excessive permissions or trick users into approving harmful transactions.

What happens if I lose my wallet?

If you lose access and don’t have a backup (like a seed phrase), you may permanently lose your assets. Always back up recovery phrases securely and never share them.


Hands-On Lab: Build a "Ping" Button for a Smart Contract

Let’s apply what we’ve learned by building a frontend that lets users trigger a "ping" on a deployed Solana program.

Step 1: Set Up Phantom in Devnet Mode

Download Phantom, create a wallet, then switch to Devnet under Developer Settings to match our test environment.

Step 2: Initialize Your Project

Use a starter Next.js template with basic structure. Install required dependencies including @solana/web3.js.

Step 3: Wrap App With Context Providers

As shown earlier, wrap your app with ConnectionProvider, WalletProvider, and WalletModalProvider.

Step 4: Add Wallet Connection UI

Replace placeholder buttons with WalletMultiButton for seamless connection flow.

Step 5: Implement the Ping Functionality

Create a button that constructs and sends a transaction to the ping program at address ChT1B39WKLS8qUrkLvFDXMhEJ4F1XZzwUNHUt4AU9aVa.

On click:

After approval, Phantom returns a transaction signature — link it to Solana Explorer for verification.


Challenge: Build a SOL Transfer dApp

Now try building independently:

  1. Allow users to send SOL from their Phantom wallet to any recipient.
  2. Include input validation and feedback messages.
  3. Enhance UX by linking to transaction explorers post-send.

Use starter code or build from scratch.

👉 Explore advanced dApp patterns used by leading blockchain projects