Solana
  • Solana Development
    • Prerequisites
    • Getting Started
      • ShadCN
      • Getting started with Next.js
    • Developing on Solana
      • Minting Solana NFTs: A Beginner's Guide
  • Examples
    • Creating a Custom Solana Wallet Connect UI
    • Portfolio Applicaiton
    • Solana Wallet Adapter
    • JavaScript Client for Mpl Core
  • Solana Cookbook
  • Wonka.JS and next.js
  • Metaplex Sugar
  • Solana Wallet Adapter To a Next.Js application
    • Basic Wallet Adapter with React
    • Integrating Solana Wallet Adapter in a Next.js Application
    • Solana Wallet Example Code and Tutorial
    • Git Hub Code
  • Token Burning Candy Machine
  • Page 1
  • DLMM
  • Page 2
  • React And Next.JS
    • Material UI
    • Installation
    • Usage
    • Example projects
Powered by GitBook
On this page
  • 1. Create a Next.js project #
  • 2. Installing Solana Wallet Adapter #
  • 4. Connect wallet button #
  • 5. useWallet and useConnection hooks #
  • Next Steps #

Solana Wallet Adapter To a Next.Js application

PreviousMetaplex SugarNextBasic Wallet Adapter with React

Last updated 1 year ago

1. Create a Next.js project

Next.js is a React framework for building full-stack web applications. You use React components to build user interfaces and Next.js for additional features and optimizations.

You will need to in order to create a Next.js app. We can execute this command, which will create a basic scaffold for us:

npx create-next-app@latest

It will ask you questions about the project name, Typescript, ESlint, tailwind CSS, src directory, using App router or not, and customizing the default import alias. For this guide, we will use all the default and recommended options for now, including using App router.

This is how the directory structure will look like after creating the scaffold:

├── src│   └── app│       ├── favicon.ico│       ├── globals.css│       ├── layout.tsx│       └── page.tsx

2. Installing Solana Wallet Adapter

In order to allow our applications users connect their favorite Solana wallet, we will need to install and use the various Solana wallet adapter packages. These packages contain essential functions, hooks, and React components required to integrate Solana wallets into our NextJS app.

To allow for better composability and smaller production builds, the "standard wallet adapter" functionality is split into a few different packages:

  • @solana/wallet-adapter-base includes functions that detect wallets the user has installed and sign/send transactions from a wallet

  • @solana/wallet-adapter-react includes the functionality to help manage the user's wallet state within your React based application, including giving access to hooks like useConnection and useWallet

  • @solana/wallet-adapter-react-ui provides several base UI components related to wallet operations, including a wallet connect/disconnect button and wallet selection modal contexts and providers

Install these packages to your Next.js project using your preferred node package manager:

npm install @solana/web3.js \    @solana/wallet-adapter-base \    @solana/wallet-adapter-react \    @solana/wallet-adapter-react-ui \    @solana/wallet-adapter-wallets \

3. Setting up Wallet Adapter in your Next.js app

This section will help you set up the Next.js app so that we can use all the Solana wallet features inside all the future pages you create.

Your folder structure should look like this:

├── src│   └── app│       ├── components│       │   └── AppWalletProvider.tsx│       ├── favicon.ico│       ├── globals.css│       ├── layout.tsx│       └── page.tsx

INFO

This AppWalletProvider.tsx file we are creating will be rendered on the client side, NOT the server side. So we will need to add the "use client" directive to the top of the file to make sure NextJS renders our context and children on the client side.

First, we will need to import all the dependencies into the file, including the standard context providers from the wallet adapter packages like connectionProvider and WalletProvider.

  • WalletAdapterNetwork is an enum that defines default network values like mainnet-beta, testnet, and devnet.

  • the WalletModalProvider from @solana/wallet-adapter-base has the context of a "connect wallet" button. This button helps you toggle the connect wallet modal component's visibility, allowing your users to select their Solana wallet to connect to your application.

  • UnsafeBurnerWalletAdapter is a react component shipped by the wallet adapter maintainers for testing wallets. This Burner Wallet is the default wallet adapter used in the starter packs. This adapter implements the Wallet Adapter interface but uses an unsafe local keypair to sign messages.

Since we are using the standard wallet adapter UI components, we also must import the provided standard CSS styles required for these react components to be displayed properly in our application. Each of these styles can be easily overridden to customize the look.

Let’s import these dependencies and use them further in the context/provider component we are building:

AppWalletProvider.tsx

"use client"; import React, { useMemo } from "react";import {  ConnectionProvider,  WalletProvider,} from "@solana/wallet-adapter-react";import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";import { clusterApiUrl } from "@solana/web3.js";// import { UnsafeBurnerWalletAdapter } from "@solana/wallet-adapter-wallets"; // Default styles that can be overridden by your apprequire("@solana/wallet-adapter-react-ui/styles.css");

There are two ways to support the various Solana wallets your user's will want to use within your application:

Our AppWalletProvider component will be used to facilitate the connection to the desired Solana network cluster (i.e. devnet, mainnet-beta, etc) via our desired RPC endpoint. This RPC endpoint will be where our application sends the transactions. In our guide here, we are hardcoded here to use the devnet network cluster.

In this example, we are also defining an array called wallets. This array contains any of the legacy wallet adapter wallets you desire to import and support within your application. Again though, you will likely not need to have any entries in this array.

AppWalletProvider.tsx

// imports here export default function AppWalletProvider({  children,}: {  children: React.ReactNode;}) {  const network = WalletAdapterNetwork.Devnet;  const endpoint = useMemo(() => clusterApiUrl(network), [network]);  const wallets = useMemo(    () => [      // manually add any legacy wallet adapters here      // new UnsafeBurnerWalletAdapter(),    ],    [network],  );   return (    <ConnectionProvider endpoint={endpoint}>      <WalletProvider wallets={wallets} autoConnect>        <WalletModalProvider>{children}</WalletModalProvider>      </WalletProvider>    </ConnectionProvider>  );}

We pass the endpoint and wallets variables into the ConnectionProvider and WalletProvider as props to those providers given to us by the wallet adapter packages. The autoConnect prop is the setting that declares whether your application should attempt to auto connect to a user's previously connected wallet when your application loads.

WalletModalProvider has a component called WalletModal which helps your users select a wallet from a list of available and installed wallets in the environment (i.e. their web browser). This provider will help that modal toggle visibility in the children components.

With our AppWalletAdapter context setup and ready-to-go, we need to wrap our NextJS application with this context to make its APIs, hooks, and state accessible within the rest of our application and child pages.

Inside your root layout.tsx, import your AppWalletAdapter provider and pass in the application's children as the children of the AppWalletAdapter component:

src/app/layout.tsx

import AppWalletProvider from "./components/AppWalletProvider"; export default function RootLayout({  children,}: Readonly<{  children: React.ReactNode;}>) {  return (    <html lang="en">      <body>        <AppWalletProvider>{children}</AppWalletProvider>      </body>    </html>  );}

With after the steps above completed and AppWalletAdapter setup properly, your NextJS application is ready to start interacting with user wallets.

The "connect wallet" button is a common component that will allow your users to open the "select wallet modal" and chose their desired Solana wallet to connect to your application.

Normally, developers add this connect wallet button component to their primary header component so that the connect button is viewable and accessible to on all other pages. Enabling users to easily connect their wallet wherever they are within your application. However, for the simplicity of this guide, we are adding the wallet connect to the home page:

In your page.tsx at the root of your app folder, import the WalletMultiButton from @solana/wallet-adapter-react-ui. Then, you can return that button component from your home page component.

src/app/page.tsx

"use client"; import { WalletMultiButton } from "@solana/wallet-adapter-react-ui"; export default function Home() {  return (    <main className="flex items-center justify-center min-h-screen">      <div className="border hover:border-slate-900 rounded">        <WalletMultiButton style={{}} />      </div>    </main>  );}

Now start your dev server and see the website served in your browser:

❯ npm run dev > my-app@0.1.0 dev> next dev    ▲ Next.js 14.1.3   - Local:        http://localhost:3000  ✓ Ready in 3.1s

Here's a demo of how output should look in your browser with the default styles provided from the wallet adapter packages:

The most common ways your application will interact with your user's Solana wallet is using the useWallet and useConnection hooks provided by the wallet adapter packages and accessible to all child components of your AppWalletAdapter context.

From the @solana/wallet-adapter-react package, you can import the two hooks named useWallet and useConnection that can be used anywhere on the client side of your app that is a child of your AppWalletAdapter context. In this example guide, it will be your entire application.

  • the useWallet hook has details like publicKey and state of the wallet, whether it’s connecting or it’s connected.

  • the useConnection hook will facilitate your application's connection to the Solana blockchain, via your RPC endpoint

INFO

const { connection } = useConnection();const { publicKey } = useWallet(); const getAirdropOnClick = async () => {  try {    if (!publicKey) {      throw new Error("Wallet is not Connected");    }    const [latestBlockhash, signature] = await Promise.all([      connection.getLatestBlockhash(),      connection.requestAirdrop(publicKey, 1 * LAMPORTS_PER_SOL),    ]);    const sigResult = await connection.confirmTransaction(      { signature, ...latestBlockhash },      "confirmed",    );    if (sigResult) {      alert("Airdrop was confirmed!");    }  } catch (err) {    alert("You are Rate limited for Airdrop");  }};

Here’s an example of getting the SOL balance of the wallet connected using the useConnection and useWallet hooks.

const [balance, setBalance] = useState<number>(0); useEffect(() => {  if (publicKey) {    (async function getBalanceEvery10Seconds() {      const newBalance = await connection.getBalance(publicKey);      setBalance(newBalance / LAMPORTS_PER_SOL);      setTimeout(getBalanceEvery10Seconds, 10000);    })();  }}, [publicKey, connection, balance]);

With functions like these and the ones provided within the wallet adapter packages, you can detect whether the user's wallet is connected or not, create a button to get an airdrop of devnet or sol in the network defined, and more.

Let’s make another page now to demonstrate how we can use each of these hooks to access actually access the connection object and your user's wallet state to send or sign transactions, read the wallet balance, and test functionality.

Create a new folder inside the app folder and name it address. Create a file page.tsx inside that folder. In this example, our new page will be located at src/app/address/page.tsx:

├── src│   └── app│       ├── address│       │   └── page.tsx│       ├── components│       │   └── AppWalletProvider.tsx│       ├── favicon.ico│       ├── globals.css│       ├── layout.tsx│       └── page.tsx

In side of your new page, we can create use utilize the hooks and custom function we discussed above to allow the user to actually perform these interactions with their Solana wallet of choice:

src/app/address/page.tsx

"use client";import { useConnection, useWallet } from "@solana/wallet-adapter-react";import { LAMPORTS_PER_SOL } from "@solana/web3.js";import { useEffect, useState } from "react"; export default function Address() {  const { connection } = useConnection();  const { publicKey } = useWallet();  const [balance, setBalance] = useState<number>(0);   // code for the `getAirdropOnClick` function here   // code for the `getBalanceEvery10Seconds` and useEffect code here   return (    <main className="flex min-h-screen flex-col items-center justify-evenly p-24">      {publicKey ? (        <div className="flex flex-col gap-4">          <h1>Your Public key is: {publicKey?.toString()}</h1>          <h2>Your Balance is: {balance} SOL</h2>          <div>            <button              onClick={getAirdropOnClick}              type="button"              className="text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700"            >              Get Airdrop            </button>          </div>        </div>      ) : (        <h1>Wallet is not connected</h1>      )}    </main>  );}

Here's what your address page will look like when the wallet is connected on the home page.

  • You can use the useWallet hook to trigger a user's connected Solana wallet to ask then to sign a transaction or a plain message that your application provides to the wallet

If you are creating a brand new application or project, you can also use the create-solana-dapp CLI took to generate a scaffold with the built-in Solana wallet adapter. To scaffold a new application, run the CLI tool in your terminal:

npx create-solana-dapp@latest

It will prompt you for common information (like your project name and desired frontend framework) and will generate a customized project, fully configured with Solana wallet adapter configured and ready for your users

Create a components folder and add a file named AppWalletProvider.tsx. We will export the contents of this file to be used inside .

AppWalletProvider.tsx

The goal of this file will be to export a as a react component that will help us “teleport” data and to use (or change) within all of the context's children components. Effectively allowing all this context's children to easily access all the Solana wallet adapter functionality and facilitate user wallet interactions within your application.

Supported wallets and "wallet standard"

Wallets with implementation. These wallets will be automatically detected with @solana/wallet-adapter-base and do not require you to add any extra code into your application for users to use them.

Wallets with are bundled in an npm package. To support these wallets within your application, you must install and import each of these wallet's legacy adapters into your application.

The most popular Solana wallets already conform to and implement wallet-standard. So for your user's to use these popular Solana wallets, you do not need to do anything special within your application. They will work automatically and be shown to your users (including ). If there is a specific, non-standard wallet that your users want your application to support, that is when we recommend manually adding it's legacy adapter.

Setup the AppWalletProvider

Wrap your application with AppWalletAdapter

4. Connect wallet button

Select and Connect Solana Wallets using Wallet Adapter

5. useWallet and useConnection hooks

Solana uses the which is transport agnostic and can be implemented over HTTP, HTTPS, WebSocket, TCP, and other transports. This means you can use the connection object returned from the useConnection hook to get or .

Performing an airdrop

Here's an example of getting a using the connection and publicKey from useConnection and useWallet hooks.

This getAirdropOnClick function gets the latest using the RPC method. It also gets the transaction signature from the function from the connection. We can also verify whether the transaction was and added to the block, ensuring the airdrop was successful and the SOL is available for use.

Getting a wallet balance

is an RPC HTTP method you can call from the connection object to get the SOL balance of any Solana account (like a user's wallet). Calling this function with setTimeout is good for checking the balance continuously every 10 seconds:

Interact with a wallet on a page

Example "address" page that uses the Solana wallet adapter hooks

Next Steps

You can call from the connection object (via the useConnection hook)

You can also checkout the from the creators of . It is an open-sourced wallet adapter alternative that adds some extra functionality, striving for the best Solana wallet integration experience for developers and the best wallet experience for your users.

#
install Node.js
#
#
the root layout file
#
context provider
#
wallet-standard
legacy wallet adapters
Solana Mobile Stack Wallet Adapter
#
#
#
#
JSON-RPC 2.0 spec
WebSocket notifications
sending HTTP requests
#
devnet SOL airdrop
blockhash
getLatestBlockhash
requestAirdrop
confirmed
#
getBalance
#
#
any RPC method
Unified Wallet Kit
Jupiter