Skip to content

Project Setup

In this section, we'll set up a NextJS project and configure it to work with Coinbase Smart Wallet.

What you'll achieve

By the end of this guide, you will:

  • Set up a NextJS project and configure it to work with Coinbase Smart Wallet
  • Create a Coinbase Wallet Context to manage the state and functions needed to interact with Coinbase Smart Wallet

Creating a New Project

We'll be using NextJS to bootstrap this project, but you can adapt these concepts to any frontend framework of your choice.

First, create a new NextJS project:

npx create-next-app@latest my-app

Navigate into the project directory:

cd my-app

Install Coinbase Wallet SDK (only on canary version for now)

npm install @coinbase/wallet-sdk@canary

Install viem for blockchain interactions

npm install viem

Note: Make sure you're using version 4.4.0 or above of the Coinbase Wallet SDK.

Project Structure

After running these commands, your project should have the following basic structure:

app/
   layout.tsx
   page.tsx

Setting up the Coinbase Wallet Context

This section will walk you through setting up Coinbase Wallet Context to manage the state and functions needed to interact with Coinbase Smart Wallet.

Create a new directory called context under the app directory and add a React Context for the Coinbase SDK.

// app/context/CoinbaseWalletContext.tsx
'use client';
import { createCoinbaseWalletSDK, ProviderInterface } from '@coinbase/wallet-sdk';
import {
  createContext,
  useContext,
  useEffect,
  useState,
  ReactNode,
  useMemo,
  useCallback,
} from 'react';
import { Address, createWalletClient, custom } from 'viem';
import { baseSepolia } from 'viem/chains';
 
interface CoinbaseWalletContextType {
  provider: ProviderInterface | null;
  connect: () => Promise<void>;
  disconnect: () => void;
  isConnected: boolean;
  address: Address | null;
}
 
const CoinbaseWalletContext = createContext<CoinbaseWalletContextType>({
  provider: null,
  connect: async () => {},
  disconnect: () => {},
  isConnected: false,
  address: null,
});
 
export function CoinbaseWalletProvider({ children }: { children: ReactNode }) {
  const [provider, setProvider] = useState<ProviderInterface | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [address, setAddress] = useState<Address | null>(null);
  useEffect(() => {
    // Initialize Coinbase Wallet SDK
    const coinbaseWalletSDK = createCoinbaseWalletSDK({
      appName: 'Coinbase Wallet demo',
      appChainIds: [baseSepolia.id],
      preference: {
        options: 'smartWalletOnly',
        keysUrl: 'https://keys-dev.coinbase.com/connect',
      },
    });
    setProvider(coinbaseWalletSDK.getProvider());
  }, []);
  const walletClient = useMemo(() => {
    if (!provider) return null;
    return createWalletClient({
      chain: baseSepolia,
      transport: custom({
        async request({ method, params }) {
          const response = await provider.request({ method, params });
          return response;
        },
      }),
    });
  }, [provider]);
 
  const connect = useCallback(async () => {
    if (!walletClient || !provider) return;
    walletClient.requestAddresses().then(async (addresses) => {
      if (addresses.length > 0) {
        setAddress(addresses[0]);
        setIsConnected(true);
      }
    });
  }, [walletClient, provider]);
 
  const disconnect = () => {
    if (!provider) return;
    try {
      provider.disconnect();
      setIsConnected(false);
      setAddress(null);
    } catch (error) {
      console.error('Failed to disconnect from Coinbase Wallet:', error);
    }
  };
 
  return (
    <CoinbaseWalletContext.Provider
      value={{
        provider,
        connect,
        disconnect,
        isConnected,
        address,
      }}
    >
      {children}
    </CoinbaseWalletContext.Provider>
  );
}
 
export function useCoinbaseWallet() {
  const context = useContext(CoinbaseWalletContext);
  if (context === undefined) {
    throw new Error('useCoinbaseWallet must be used within a CoinbaseWalletProvider');
  }
  return context;
}

Creating the Provider Wrapper

Create a providers file to wrap your application:

// app/providers.tsx
 
'use client';
import { CoinbaseWalletProvider } from '@/context/CoinbaseWalletContext';
 
export default function Providers({ children }: { children: ReactNode }) {
  return <CoinbaseWalletProvider>{children}</CoinbaseWalletProvider>;
}

Updating the Root Layout

Update your root layout to include the providers:

// app/layout.tsx
 
import Providers from '@/app/providers';
 
export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Creating the Home Page

Update your main page to include wallet connection functionality:

// app/page.tsx
 
'use client';
import { useCoinbaseWallet } from './context/CoinbaseWalletContext';
export default function Home() {
  const { isConnected, connect, disconnect, address } = useCoinbaseWallet();
  return (
    <div>
      {isConnected ? (
        <div>
          <p>Connected address: {address}</p>
          <button onClick={disconnect}>Disconnect Wallet</button>
        </div>
      ) : (
        <button onClick={connect}>Connect Wallet</button>
      )}
    </div>
  );
}

Testing the Setup

  1. Start your development server:
npm run dev
  1. Open your browser and navigate to http://localhost:3000.
  2. Click the "Connect Wallet" button to connect your Coinbase Smart Wallet.
  3. After connecting, you should see your wallet address displayed on the page

Now that you have the basic setup complete, you're ready to start implementing Sub Accounts! Continue to the next section to learn how to create Sub Accounts for your users.

Next Steps

In the next section, we'll cover Creating Sub Accounts and how to integrate them into your application.