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 } 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]);

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

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

The useEffect pattern above works because createSolanaClient typically resolves before the user opens the wallet modal. If MetaMask does not appear in the wallet list, ensure createSolanaClient has resolved before the WalletProvider renders. One approach is to 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.