For AI agents: a documentation index is available at /llms.txt. A markdown version of this page is available at the same URL with .md appended (or via Accept: text/markdown).
Skip to main content

Use the Wallet Adapter

Solana's Wallet Adapter is the standard way for Solana dapps to discover and connect to wallets. MetaMask Connect Solana implements the Wallet Standard, so it works with the Wallet Adapter out-of-the-box.

This guide shows you how to set up the Wallet Adapter with MetaMask in a React dapp. You can also use the create-solana-dapp CLI tool to generate a new project with the Wallet Adapter built in.

Prerequisites

  • Node.js version 19 or later
  • A package manager such as npm, Yarn, pnpm, or bun
  • A React or Next.js project

Steps

1. Install dependencies

Install MetaMask Connect Solana and the Wallet Adapter packages:

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

2. Create the Solana provider

Create a SolanaProvider component that initializes MetaMask Connect Solana and wraps the Wallet Adapter providers:

components/SolanaProvider.tsx
'use client';

import React, { FC, ReactNode, useEffect, useMemo, useState } 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 { createSolanaClient } from '@metamask/connect-solana';

import '@solana/wallet-adapter-react-ui/styles.css';

interface SolanaProviderProps {
children: ReactNode;
}

export const SolanaProvider: FC<SolanaProviderProps> = ({ children }) => {
const network = WalletAdapterNetwork.Devnet;
const endpoint = useMemo(() => clusterApiUrl(network), [network]);
const [ready, setReady] = useState(false);

useEffect(() => {
createSolanaClient({
dapp: {
name: 'My Solana Dapp',
url: window.location.origin,
},
}).then(() => setReady(true));
}, []);

// Wait for createSolanaClient to resolve before mounting WalletProvider, so MetaMask
// is registered with the Wallet Standard registry before the wallet list renders.
if (!ready) {
return null;
}

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

Calling createSolanaClient registers MetaMask with the Wallet Standard registry. This displays MetaMask as a connection option in the wallet modal, even if the user doesn't have MetaMask installed.

Timing

MetaMask only appears in the wallet modal if createSolanaClient has resolved before the WalletProvider mounts. The example above gates rendering on a ready flag to guarantee this. As an alternative, await the client in your app's entry point before calling createRoot().render(). See Troubleshooting: MetaMask wallet not appearing for details.

3. Add the provider to your root layout

Wrap your application with SolanaProvider so all components can access the wallet context:

import './globals.css';
import '@solana/wallet-adapter-react-ui/styles.css';
import { SolanaProvider } from '@/components/SolanaProvider';

export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html>
<body>
<SolanaProvider>{children}</SolanaProvider>
</body>
</html>
);
}

4. Add a connect button

Use the Wallet Adapter's WalletMultiButton component to add a connect button to your dapp:

components/ConnectWallet.tsx
'use client';

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

export const ConnectWallet = () => {
return <WalletMultiButton />;
};

The button automatically displays a wallet selection modal that includes MetaMask.

Chrome Android

There is a known issue with @solana/wallet-adapter-react on Chrome Android when used with the Wallet Standard provider from @metamask/connect-solana. Test Solana Wallet Adapter flows on desktop Chrome and the MetaMask browser extension before targeting mobile. See Troubleshooting for details.

Next steps

See how to send a legacy transaction and a versioned transaction.