How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (2024)

19 min read

Overview

Been building on Solana and ready to bring your dApp to the web? You're going to need a way to connect your tools to your users' wallets. Though there are a few ways to connect your dApp to your users' wallets, Solana has created a couple of handy tools that make getting started easy: Solana Wallet Adapter and Solana dApp Scaffold.

What You Will Do

  • Learn what Solana Wallet Adapter is
  • Deploy the Solana dApp Scaffold
  • Customize your environment
  • Create a simple dApp to query a Connected Wallet

What You Will Need

  • Nodejs (version 16.15 or higher)
  • A Solana wallet (e.g. Phantom)
  • Experience with [Solana Web3] and Solana SPL Token Library
  • Typescript experience and ts-node installed
  • Basic knowledge of HTML/CSS
  • Experience with front-end web development will be helpful but not required to follow along. We'll be creating a Next.js project using React. The Solana community also supports Vue, Angular, and Svelte. Visit their community page for more information.

What is the Wallet Adapter

Ever notice that many Solana dApps have a similar-looking UI for connecting to Wallets?

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (1)

That's the Solana Wallet Adapter ("SWA"), and you see it in lots of places because it is easy to use, inclusive of all of the most common wallets on Solana, and regularly maintained by the Solana Community. So what is it? The SWA is a set of Modular TypeScript wallet adapters and components for Solana applications that allow you to easily connect your dApp to your users' wallet of choice (over a dozen Solana wallets are supported out of the box!).

Here are some reasons to consider using SWA:

  1. Open source, supported by Solana-labs
  2. Multi wallet support: let your users use their wallet of choice without a creating a bunch of headaches for you to support new wallets
  3. Includes an off-the-shelf customizable UI
  4. Includes Anchor support
  5. Key Functionality built-in: Connect, Disconnect, Auto-connect
  6. Supports multiple front-end frameworks

Let's try it out!

Set Up Your Environment

SWA includes support for multiple front-end frameworks:

  • React
  • Material-UI,
  • Ant Design
  • Angular Material UI
  • Vue (community-supported)
  • Angular (community-supported)
  • Svelte (community-supported)

You can add these packages to your existing projects using npm instructions here. For this example, however, we will be creating a new project using the Solana dApp Scaffold. The dApp Scaffold includes SWA and a few pre-built components to make it quick for you to get up and running!

Note: if you are adding the adapter to an existing project, the current SWA at the time of this writing does not support React 18. Please use React 17.

Create a new project directory in your terminal with:

mkdir my-solana-dapp
cd my-solana-dapp

Clone the dApp Scaffold:

git clone https://github.com/solana-labs/dapp-scaffold.git . 

The `.` will clone the scaffold into your project directory without creating a new directory inside of it.

Type ls in your terminal to make sure everything got copied correctly. Your terminal should look something like this:

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (2)

Install dependencies:

npm install
# or
yarn install

Also go ahead and add the SPL-token Library, which we'll use later in this exercise:

npm i @solana/spl-token
# or
yarn add @solana/spl-token

Adding a QuickNode Custom RPC Endpoint

To build on Solana, you'll need an API endpoint to connect with the network. You're welcome to use public nodes (which are already integrated into the Scaffold) or deploy and manage your own infrastructure; however, if you'd like 8x faster response times, you can leave the heavy lifting to us. See why over 50% of projects on Solana choose QuickNode and sign up for free here.

We're going to launch our node under the Solana Devnet, but you can launch the node that meets your needs. Copy the HTTP Provider link:

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (3)

Then, navigate back to your terminal, and create an .env file with the following command from your my-solana-dapp directory:

echo > .env

We encourage using an .env to protect your key when creating a production site.

Open your project in a code editor of choice and navigate to your newly created .env file. Declare two variables, REACT_APP_SOLANA_RPC_HOST and REACT_APP_NETWORK. Paste your RPC url in the REACT_APP_SOLANA_RPC_HOST variable and set your REACT_APP_NETWORK to the Solana cluster you'll be using (devnet, mainnet-beta, or testnet). This should be the same network that you selected your RPC endpoint from. Your file should look something like this:

REACT_APP_SOLANA_RPC_HOST=https://example.solana-devnet.quiknode.pro/00000000000/
REACT_APP_NETWORK=devnet

We must also update next.config.js to use these environment variables in our Next.js app. Open the file in your root project directory and replace the contents with this:

/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}

module.exports = {
nextConfig,
env: {
REACT_APP_SOLANA_RPC_HOST: process.env.REACT_APP_SOLANA_RPC_HOST,
REACT_APP_NETWORK: process.env.REACT_APP_NETWORK
}
}

Now update the Scaffold's endpoint by opening ./src/contexts/ContextProvider.tsx and replacing lines 20-21:

 const network = WalletAdapterNetwork.Devnet;
const endpoint = useMemo(() => clusterApiUrl(network), [network]);

with

 const network = process.env.REACT_APP_NETWORK as WalletAdapterNetwork;
const endpoint = process.env.REACT_APP_SOLANA_RPC_HOST;

We're all set! Let's launch our app!

npm run dev
# or
yarn dev

If you have followed all of the steps to this point, you should be able to go to http://localhost:3000/ and see your scaffold. Nice work! You should see something like this:

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (4)

Feel free to click around and explore the scaffold. You can Connect a Wallet and request an airdrop (devnet & testnet), sign a message, or send SOL to a random wallet.

Orienting to Solana Wallet Adapter and Scaffold

Before making our component, let's look around our workspace to better understand how everything is working. Without going too deep into what is going on with the React here, let's cover a few essential pieces relevant to Solana dApps.

Wallet Connect Button

Check out /my-solana-dapp/src/components/AppBar.tsx. You should see that we import WalletMultiButton from solana/wallet-adapter-react-ui. This button, <WalletMultiButton className="btn btn-ghost mr-4" /> is how the user interacts with our wallet adapter. You'll also notice here the use of the setAutoConnect method set the user toggle. We won't change anything here, but if you want to set or disable autoConnect you could use this form.

Connection Context

Next check out /my-solana-dapp/src/contexts/ContextProvider.tsx. This file is where we updated our endpoint and network earlier and is the home of the Wallet Context Provider, where we can configure the Wallet Adapter.

  • First, notice our wallets variable. You'll notice a list of common Solana wallets listed. Try commenting one or more out with // or removing the comments on new SlopeWalletAdapter() (in the imports, lines 4-11 AND in the declarations, lines 22-35). Refresh your site and connect your wallet. You should notice that the list of available wallets has changed. Effectively, the wallets variable gets passed into the Wallet Adapter through the Wallet Provider Component to set which wallets will be allowed on our dApp.
  • autoconnect determines how the users' wallet interacts with the site on load. As we discussed earlier, our AppBar toggle allows the user to control this on the site UI.
  • onError tells our program how to handle errors
  • endpoint and network set how your app will connect with the Solana network
  • The Scaffold has come configured for us, but if you are setting up your project without the Scaffold, you'll need to make sure this context surrounds your app. You can see where this is done in /my-solana-dapp/src/pages/_app.tsx: <ContextProvider> is parent to our AppBar and ContentContainer.

Components

Before moving on, check out the Components folder, /my-solana-dapp/src/components. You'll see components associated with each of our app's pre-existing tools/buttons (e.g., Airdrop, Sign Message, Send Transaction). Feel free to explore a couple of these files to see how they work--we will be making our own in just a moment! If you're not familiar with React, that's fine. Just know that each of these files, or components, is basically a building block to our website. We drop those building blocks in the appropriate sites (for example, you can see the RequestAirdrop called in the Home View page: /my-solana-dapp/src/views/home/index.tsx).

Create a Custom Component for your dApp

Now that we have our dApp environment established and know how it works, let's add our component! For this exercise, we're going to use a script we developed in another tutorial to get all of the token accounts associated with an owner's wallet (accessible here).

Create a Reusable Component Template

Let's make a component template that we can use for this exercise and that you can also use to easily create new components in the future.

Create a new file in the components directory called template.tsx. In your terminal, stop the server with a CTRL+C and enter the following command:

echo > ./src/components/template.tsx

Open template.tsx and paste this code, then save.

import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { FC, useState } from 'react';
import { notify } from "../utils/notifications";
//Add import dependencies here

export const Template: FC = () => {
const { connection } = useConnection();
const { publicKey } = useWallet();

//State Variables here

//dApp Scripts here

return(<div>

{/* Render Results Here */}

</div>)
}

Set Up Your Component

This creates a shell for a React component that we can use to add our own functionality! Copy the template and save as a new file called GetTokens.tsx.

cp ./src/components/template.tsx ./src/components/GetTokens.tsx

In GetTokens.tsx, rename the component by changing export const Template to:

export const GetTokens

For our tool that looks at a wallet's token accounts, we'll need to add a couple of additional dependencies to help us interact with the SPL Token Library. Add these under Add import dependencies here:

import { GetProgramAccountsFilter } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

Let's set up a new state variable, tokenTable using setState (if you're not familiar with React, that's fine--this is some of the magic that will help our results render to the page after we've found what we're looking for). Add the following code just after the State Variables here comment in the template:

 const [tokenTable, setTokenTable] = useState(null);

Create Your Query

We've gone ahead and modified the code from our existing QuickNode guide on How to Get All Tokens Held By a Wallet in Solana slightly to be React-friendly. Specifically instead of using console.log to display our results, we want to write the results to a table (as a JSX Element) that can be rendered on our website.

Go ahead and add this code underneath your state variable //dApp Scripts Here and before return():

 async function getTokenAccounts(wallet: string) {
const filters:GetProgramAccountsFilter[] = [
{
dataSize: 165, // number of bytes
},
{
memcmp: {
offset: 32, // number of bytes
bytes: wallet, // base58 encoded string
},
}];
const accounts = await connection.getParsedProgramAccounts(
TOKEN_PROGRAM_ID, // new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
{
filters: filters,
}
);
console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}: `);
if(accounts.length === 0) {
return(<div>No Token Accounts Found</div>)
}
else{
const rows = accounts.map((account,i)=>{
//Parse the account data
const parsedAccountInfo:any = account.account.data;
const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
return (
<tr key={i+1}>
<td key={'index'}>{i+1}</td>
<td key={'mint address'}>{mintAddress}</td>
<td key={'balance'}>{tokenBalance}</td>
</tr>)
})
const header = (<tr>
<th>Token No.</th>
<th>Mint Address</th>
<th>Qty</th>
</tr>)
setTokenTable(<table>{header}{rows}</table>)
}
}

You'll see that our .map method returns a <tr> row for every account found. When invoked, the getTokenAccounts method should fetch all token accounts from the chain, create a table element with the results, and use react to add the table element to our state. We've also added some logic to let the user know if there were no SPL token accounts found.

Create a Click Handler

In order to invoke getTokenAccounts, create a function called onClick that we can hook to a button on our page. The button will:

  1. Check if a wallet is connected. We can do this by checking if publicKey is found from our useWallet() method from the Wallet Adapter.
  2. Try to getTokenAccounts for the connected wallet (note that we need to convert our public key to a string to use it in our filter parameters, using .toString()).
  3. Handle errors.
 const onClick = async () => {
if (!publicKey) {
console.log('error', 'Wallet not connected!');
notify({ type: 'error', message: 'error', description: 'Wallet not connected!' });
return;
}
try {
await getTokenAccounts(publicKey.toString());

} catch (error: any) {
notify({ type: 'error', message: `Couldn't Find Token Accounts!`, description: error?.message });
console.log('error', `Error finding Token Accounts! ${error?.message}`);
}
};

Create a Button

Inside of your component's return(), you'll see a <div>. Create a button inside of it that calls our onClick function. We're using the same CSS as used elsewhere in the template. Feel free to customize!

 <div className="text-center">
<button
className="px-8 m-2 btn animate-pulse bg-gradient-to-r from-[#9945FF] to-[#14F195] hover:from-pink-500 hover:to-yellow-500"
onClick={onClick}
>
<span>Get Token Accounts</span>
</button>
</div>

Render Results

Now display your results by calling the tokenTable state variable that we set with getTokenAccounts. Inside your div and after the Render Results Here comment, add:

 <div>{tokenTable}</div>

Because we don't define a variable until after our token query, this will just be blank until the program has found anything.

Here's what our Component looks like now that we're done:

import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { FC, useState } from 'react';
import { notify } from "../utils/notifications";
//Add import dependencies here
import { GetProgramAccountsFilter } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

export const GetTokens: FC = () => {
const { connection } = useConnection();
const { publicKey } = useWallet();

//State Variables here
const [tokenTable, setTokenTable] = useState(null);

//dApp Scripts here
async function getTokenAccounts(wallet: string) {
const filters:GetProgramAccountsFilter[] = [
{
dataSize: 165, // number of bytes
},
{
memcmp: {
offset: 32, // number of bytes
bytes: wallet, // base58 encoded string
},
}];
const accounts = await connection.getParsedProgramAccounts(
TOKEN_PROGRAM_ID, // new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
{
filters: filters,
}
);
console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}: `);
if(accounts.length === 0) {
return(<div>No Token Accounts Found</div>)
}
else{
const rows = accounts.map((account,i)=>{
//Parse the account data
const parsedAccountInfo:any = account.account.data;
const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
return (
<tr key={i+1}>
<td key={'index'}>{i+1}</td>
<td key={'mint address'}>{mintAddress}</td>
<td key={'balance'}>{tokenBalance}</td>
</tr>)
})
const header = (<tr>
<th>Token No.</th>
<th>Mint Address</th>
<th>Qty</th>
</tr>)
setTokenTable(<table>{header}{rows}</table>)
}

}

const onClick = async () => {
if (!publicKey) {
console.log('error', 'Wallet not connected!');
notify({ type: 'error', message: 'error', description: 'Wallet not connected!' });
return;
}
try {
await getTokenAccounts(publicKey.toString());

} catch (error: any) {
notify({ type: 'error', message: `Couldn't Find Token Accounts!`, description: error?.message });
console.log('error', `Error finding Token Accounts! ${error?.message}`);
}
};

return(<div>
<div className="text-center">
<button
className="px-8 m-2 btn animate-pulse bg-gradient-to-r from-[#9945FF] to-[#14F195] hover:from-pink-500 hover:to-yellow-500"
onClick={onClick}
>
<span>Get Token Accounts</span>
</button>
</div>
{/* Render Results Here */}
<div>{tokenTable}</div>
</div>)
}

Great job! You've not built your first dApp component using the Solana Scaffold. Time to add it to the site.

Deploy Your Component

Now let's add our component to our homepage. Open up the home view, /my-solana-dapp/src/views/home/index.tsx. Since we created a new component, we must import it before using it. Add this import to line 14:

import { GetTokens } from 'components/GetTokens';

Let's add our component below the existing airdrop button and wallet ballance display:

 <div>
<RequestAirdrop />
{/* ... */}
</div>
{/* ADD THIS 👇 */}
<div>
<GetTokens/>
</div>

I don't know about you, but I'm ready to see this thing in action. Let's run it!

npm run dev
# or
yarn dev

There's our beautiful button!

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (5)

If you get trigger happy like me, you will probably get an error message because you have not connected a wallet yet (remember when we set that error?):

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (6)

Connect your wallet by clicking Select Wallet in the top right corner. Select your preferred wallet. You should see your Solana balance once your wallet is connected.
Alright, NOW you can click "Get Token Accounts"... BOOM! Do you see something like this?

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (7)

If you don't have any tokens in your wallet yet, you can check out our guide on minting NFTs with Candy Machine to get going.

Having fun? Feel free to continue building on this and even throw in some custom CSS to make that table look however you'd like!

Wrap Up

Congrats! You made it! And we have covered a lot. After completing this exercise, you can now build your own dApps with the Solana dApp Scaffold and Wallet Adapter. This is an excellent foundation for jumping into all sorts of things, so we will be building more components from this foundation in the future!

Find this useful? Check out some of our other Solana tutorials here. Subscribe to our newsletter for more articles and guides on Solana. Feel free to reach out to us via Twitter if you have any feedback. You can always chat with us on our Discord community server, featuring some of the coolest developers you'll ever meet 😎

We ❤️ Feedback!
Wanna share your thoughts on this guide? We'd love to hear it!

How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold | QuickNode (2024)

FAQs

How to connect Solana wallet to DApp? ›

Integrating with Solana wallets
  1. Install Solana wallet libraries.
  2. Initialise the wallet store.
  3. Use wallet UI components.
  4. Update the design of the wallet button.
  5. Connect your wallet.
  6. Access wallet data.
  7. We need more data.
  8. Provide a workspace.

How do I connect my DApp to my wallet? ›

Using the WalletConnect scan button
  1. On the “dApps” tab in the bottom right corner select the WalletConnect button. The QR code scanner will appear.
  2. Select "WalletConnect" as a connection method inside the dApp.
  3. Scan the QR code with your mobile device from step 1.

How to connect Solana wallet in React? ›

If you go through the source code for the React UI package, then you will notice that it makes use of the useWallet hook from the @solana/wallet-adapter-react package. It also has the required components (buttons, modals, providers) and styling to be an easy-to-use library to implement a connect wallet feature.

How do I connect to Solana Blockchain? ›

The following outlines the process for bridging using Portal.
  1. Step 1: Select the blockchains. ...
  2. Step 2: Connect the wallet. ...
  3. Step 3: Select an asset to transfer. ...
  4. Step 4: Connect the Solana wallet. ...
  5. Step 5: Create associated token account. ...
  6. Step 6: Bridge the funds. ...
  7. Step 7: Redeem the funds. ...
  8. Step 1: Transfer the funds to the wallet.
Feb 28, 2024

How do you manually connect to a dApp? ›

Does this article need to be translated?
  1. In MetaMask, click on the three dots menu in the upper right corner, and then on Connected sites:
  2. Click the Manually connect to current site button at the bottom of the list.
  3. Next, select the account(s) you want to connect, then follow the prompts to confirm the process:

What happens when you connect your wallet to a dApp? ›

In other words, when you connect to a DApp via WalletConnect, it's impossible for the funds in your wallet to be spent without your approval. That being said, any time you (purposely) send cryptoassets to a smart contract, there are risks (see below). Read more: Common dApp risks and how to avoid them.

What is the difference between DApp and wallet? ›

a dApp is a decentralized application. It means that part or the whole logic of the application is stored on a network. A digital wallet is what it means, a wallet that stores coins or units of value on a file or in an application.

How do I connect my DApp to my Coinbase wallet? ›

If you are on a dapp that requires a wallet to proceed, look for the option to Connect Coinbase Wallet. When you select that option, you will be presented with a QR code. Scan that QR code by tapping the QR scanner in the Wallet app.

What is a DApp URL? ›

A decentralized application (DApp) is a type of distributed, open source software application that runs on a peer-to-peer (P2P) blockchain network rather than on a single computer. DApps are similar to other software applications that are supported on a website or mobile device, but they're P2P supported.

How do I activate my Solana wallet? ›

How to get a Solana wallet
  1. Download and install Trust Wallet.
  2. Add Solana (SOL) to your wallet.
  3. Access wallet features like buy, sell, swap and more.

What is a wallet adapter? ›

The wallet adapter helps you to integrate many different wallets at once and use the same interface to interact with any supported wallet.

Which wallet is best for Solana? ›

1. Phantom Wallet: Most Versatile Multi-Chain Wallet for Solana. As the official Solana wallet, Phantom is a prominent wallet in the Solana ecosystem, known for its robust features that cater to both new and experienced users.

What is the secret key in Solana wallet? ›

Secret key #

The secret key (also referred to as private key) is required to digitally sign any transactions to send cryptocurrencies to another address or to make any changes to the wallet. The secret key must never be shared.

How do I connect my Solana wallet to my ledger? ›

On desktop
  1. Go to Solflare.
  2. Connect your Ledger device and open the Solana app. ...
  3. Click Access Wallet.
  4. Select Ledger > Continue.
  5. Click Continue then select your Ledger device and click Connect.
  6. Choose and confirm a password then click Continue.
  7. Select m/44'/501'/0' for the derivation path.
Mar 26, 2024

Top Articles
What Is a Firewall? Ultimate Guide to Types, Benefits & More
Budget 2024 Income Tax Slabs FY25 Highlights: No changes in tax rates; know income tax slabs & tax rates for 2024-25 - The Times of India
Pikes Suwanee
Fbsm St Louis
Christine Paduch Howell Nj
Christine Paduch Howell Nj
Woman who fled Saudi Arabia reaches her new home in Canada
Pjstar Obits Legacy
Frivlegends.com Unblocked
Indianapolis Star Obituary
Loss Payee And Lienholder Addresses And Contact Information Updated Daily Free List Bank Of America
Argus911
Welcome To Aces Charting
Die eID-Karte für Bürgerinnen und Bürger der EU und des EWR
Michelle_Barbelle
Snohomish Hairmasters
Best Pizza In Westlake
Shadow Under The Mountain Skyrim
Oviedo Anonib
Sprinter Tyrone's Unblocked Games
Craigs List Rochester
Southern Food Buffet Near Me
2068032104
Sevierville, Tennessee: Idyllisches Reiseziel in den Great Smoky Mountains
Will Certifier Crossword Clue
Pge Outage Map Beaverton
Reahub 1 Twitter
Berklee College Of Music Academic Calendar
Forza Horizon 5: 8 Best Cars For Rally Racing
Dynasty League Forum
Panty Note 33
Brake Masters 228
Craigslist Pets Seattle Tacoma Washington
Craigslist Ct Apartments For Rent
Restaurants Near 275 Tremont St Boston
R/Sandiego
Gabrielle Abbate Obituary
Sparkle Nails Phillipsburg
Lily Starfire White Christmas
Tj Nails Victoria Tx
Wv Mugshots 2023
Burlington Antioch Ca
Sarah Colman-Livengood Park Raytown Photos
Sierra At Tahoe Season Pass Costco
Norwegian Luna | Cruise Ship
Gun Show Deridder La
Watch Wrestling.up
Nuefliks.com
MERRY AND MARRIED MERRY & MARRIED MERRY + MARRIED MERRY E MARRIED MERRY ; MARRIED MERRY, MARRIED MERRY - MARRIED Trademark Application of Nexus Integrity Group - Serial Number 98485054 :: Justia Trademarks
1V1 Google Classroom
Bourbon Moth Magnolia
What Is Opm1 Treas 310 Deposit
Latest Posts
Article information

Author: Annamae Dooley

Last Updated:

Views: 6050

Rating: 4.4 / 5 (65 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Annamae Dooley

Birthday: 2001-07-26

Address: 9687 Tambra Meadow, Bradleyhaven, TN 53219

Phone: +9316045904039

Job: Future Coordinator

Hobby: Archery, Couponing, Poi, Kite flying, Knitting, Rappelling, Baseball

Introduction: My name is Annamae Dooley, I am a witty, quaint, lovely, clever, rich, sparkling, powerful person who loves writing and wants to share my knowledge and understanding with you.