Get Started with Coinbase Smart Wallet

Get Started with Coinbase Smart Wallet

ยท

7 min read

In this tutorial, I'll walk you through the process of setting up Coinbase Smart Wallet inside a front-end application. By the end of the tutorial, we'll build a simple Next.js application where users can:

  1. Connect to your application via Coinbase Smart Wallet.

  2. Perform transactions from their newly created wallet.

  3. Pay no gas fees! Thanks to the power of paymasters to cover user's gas fees.

Below is a quick demo video of what we'll build:

Coinbase Smart Wallet demo

If it sounds like you're in the right place, great! Let's get started!

Setting Up the Project

If you prefer to start from the complete code, the full source code is available on GitHub below, with instructions in the README on how to get started locally.

For those starting from scratch, create a simple Next.js app using npx create next-app:

pnpm create next-app@latest coinbase-smart-wallet-demo --typescript --tailwind --eslint

Next, install the thirdweb React SDK which includes the ConnectButton component:

# Ensure you run the command from the coinbase-smart-wallet-demo directory
pnpm i thirdweb

thirdweb API Key

To instantiate the thirdweb React SDK, you'll need a thirdweb API key To get one:

  1. Head to the Settings tab on the thirdweb dashboard.

  2. Click + Create API Key.

  3. Give your key a name and set the allowed domains.

  4. Click Next and copy your app's Client ID.

thirdweb API key setup demo

To keep things brief for the tutorial, I'll store my thirdweb client ID in plain text, however, you should keep the values safe, using environment variables.

Nice! All our setup is done. This gives us everything we need to build our app.

Integrating Coinbase Smart Wallet

We'll break down the Coinbase Smart Wallet integration into three steps:

  1. Wrapping our application in the ThirdwebProvider.

  2. Adding the ConnectButton component.

  3. Showcasing a simple test transaction with a TransactionButton component.

Wrapping the App in the ThirdwebProvider

The thirdweb SDK uses a provider pattern, meaning we wrap our application with a ThirdwebProvider component to use thirdweb SDK features throughout our code.

First, wrap your application in the ThirdwebProvider component like so:

// File: src/app/layout.tsx
import { ThirdwebProvider } from "thirdweb/react";

export default function RootLayout({ children }) {
  return (
      <ThirdwebProvider>
        <body>{children}</body>
      </ThirdwebProvider>
  );
}

Adding the Connect Wallet Button

The thirdweb SDK includes a ConnectButton component that opens a modal and allows users to connect their wallets. We'll use it to show the Coinbase Smart Wallet prompt.

Using the code below, we can render a "Connect Wallet" button that prompts the user to connect to our application using Coinbase Smart Wallet, by:

  1. Importing what chain we want to use from the thirdweb/chains package.

  2. Rendering the ConnectButton from the thirdweb SDK.

    • Providing your thirdweb client ID to the createThirdwebClient function.

    • Calling the createWallet function with com.coinbase.wallet (Coinbase Wallet).

    • Setting smartWalletOnly to disable the Coinbase Wallet Browser Extension.

// File: /src/app/page.tsx
"use client"; // thirdweb SDK doesn't support server-side rendering yet.

import { createThirdwebClient } from "thirdweb"; // Create the thirdweb client with your client ID
import { ConnectButton } from "thirdweb/react"; // The component we can prompt the user to connect their wallet with
import { createWallet } from "thirdweb/wallets"; // Function to specify we want to use Coinbase smart wallet
import { polygon } from "thirdweb/chains"; // Import the the blockchain you want to use

export default function Home() {
  return (
    <>
      <ConnectButton
        client={createThirdwebClient({
          clientId: "your-thirdweb-client-id-goes-here",
        })}
        wallets={[
          createWallet("com.coinbase.wallet", {
            walletConfig: {
              // Specify we do not want coinbase wallet browser extension support, just smart wallet
              options: "smartWalletOnly",
            },
            chains: [polygon],
          }),
        ]}
      />
    </>
  );
}
๐Ÿ’ก
Ensure you replace the placeholder value with your thirdweb client ID!

That's all we need for our Coinbase Smart Wallet integration! ๐ŸŽ‰ To see it in action, run pnpm run dev and visit http://localhost:3000/ in your browser and try it out:

Coinbase Smart Wallet demo

๐Ÿ’ก
Depending on what device you are using (Windows, Mac, Android, etc.) the options to save your passkey will be different.

Submitting Transactions from Coinbase Smart Wallet

Next, let's showcase a simple smart contract interaction with this connected wallet.

For this tutorial, I've deployed a simple Edition Drop smart contract using the thirdweb dashboard. This ERC-1155 NFT smart contract (deployed here) allows users to mint NFTs for free; perfect for us to showcase Coinbase Smart Wallet.

If you want to follow the same steps, you can:

  1. Deploy an Edition Drop smart contract.

  2. Select the NFTs tab and lazy mint metadata for an NFT.

  3. Set up a free, public claim phase for your NFT.

Beneath our ConnectButton, let's add a TransactionButton so users can submit the transaction of minting an NFT from the drop from their Coinbase Smart Wallet.

First, import some relevant functions and components we'll be using from thirdweb:

import { TransactionButton, useActiveAccount } from "thirdweb/react";
import { claimTo } from "thirdweb/extensions/erc1155";
import { getContract } from "thirdweb";

Let's also abstract out the chain and thirdweb client into variables:

// You can safely place these *outside* of the component
const thirdwebClient = createThirdwebClient({
  clientId: "your-thirdweb-client-id-goes-here",
});

const chainToUse = polygon;

Get the address of the connected Coinbase Smart Wallet using useActiveAccount:

// Place this *within* the component
const account = useActiveAccount();

Then, render the TransactionButton component beneath the existing ConnectButton component. We can use the getContract function to connect to our smart contract, and call the claimTo function to claim/mint an NFT from the drop:

<TransactionButton
  transaction={() =>
    claimTo({
      contract: getContract({
        client: thirdwebClient,
        chain: chainToUse,
        address: "0x-your-smart-contract-address-goes-here",
      }),
      quantity: BigInt(1), // Mint 1 NFT
      to: account?.address, // To the connected Coinbase Smart Wallet address
      tokenId: BigInt(0), // Of NFT with token ID of 0
    })
  }
  payModal={false} // Disable the FIAT on-ramp dialogue (optional)
>
  Mint NFT
</TransactionButton>
๐Ÿค“
You can get your smart contract address from the thirdweb dashboard. Ensure you replace the placeholder value in the above code snippet.

Let's test out this transaction button on http://localhost:3000/ now:

Account abstraction without a paymaster

๐Ÿ˜ฑ Oh no! Our users don't have any funds in their wallets to pay for these gas fees... if only there was a way to cover our user's gas fees somehow! ๐Ÿ˜‰

Sponsoring User Gas Fees with a Paymaster

Paymasters are a feature of ERC-4337 account abstraction, which is how Coinbase Smart Wallet works under the hood (a topic for another blog post).

They allow the gas fee of a transaction to be "sponsored" (paid for) by a different wallet than the one submitting the transaction; typically, the developer of the application sponsors the gas fees of user transactions.

The thirdweb SDK provides specific EIP-5792 hooks for us to accomplish this sponsorship. Let's first import the one we're going to use, useSendCalls:

import { useSendCalls } from "thirdweb/wallets/eip5792";

Then, let's refactor the claiming code we wrote previously into a new, separate function, so we can include some paymaster logic:

async function sendSponsoredTransaction() {

  // Our existing claim code placed here in a claimTx variable
  const claimTx = claimTo({
    contract: getContract({
      client: thirdwebClient,
      chain: chainToUse,
      address: "0x-your-smart-contract-address-goes-here",
    }),
    quantity: BigInt(1),
    to: account?.address,
    tokenId: BigInt(0),
  });
  // End existing code

  return await sendCalls({
    calls: [claimTx], // We can even put multiple transactions here
    capabilities: {
      // We cover the gas fees of the transaction for the user!
      paymasterService: {
        // Docs: https://portal.thirdweb.com/connect/account-abstraction/infrastructure
        url: `https://${chainToUse.id}.bundler.thirdweb.com/${thirdwebClient.clientId}`,
      },
    },
  });
}

Finally, modify the TransactionButton from earlier to call the sendSponderedTransaction function, instead of directly calling the claimTo function, like so:

<TransactionButton transaction={() => sendSponsoredTransaction()}>
  Mint NFT
</TransactionButton>

Sponsoring Transactions on Mainnet

On testnets such as Base Sepolia (baseSepoliain the thirdweb chains package), it's free to cover the gas fees of users with the thirdweb SDK.

To sponsor transactions on mainnet environments, however, real funds are being used. Therefore, you need to provide a credit card on the billing tab of the thirdweb dashboard to pay for these fees. Note: you don't need to upgrade to the growth tier.

You can read more details on thirdweb's bundler documentation.

Configuring Sponsorship Rules

When dealing with real funds (if you're using mainnet), you want to ensure you are only covering the fees of specific transactions that you want to sponsor, not just any transaction!

Thankfully, thirdweb makes this easy to configure from the dashboard within the account abstraction configuration section. This allows you to specify exactly what chains, smart contracts, and wallets you want to cover the gas fees for.

For example, I configured my sponsorship rules to:

  • Only sponsor transactions on the Polygon chain.

  • Only sponsor transactions interacting with my NFT smart contract.

thirdweb Account abstraction sponsorship rules

Alright! We're finally done! Let's see the final demo in action:

Wrapping Up

That's it! We've built a simple application where anybody can mint an NFT for free; without setting up a wallet, writing down seed phrases, or paying any gas fees!

Got questions or feedback? Reach out to me on Twitter @jarrodwattsdev

Did you find this article valuable?

Support Jarrod Watts by becoming a sponsor. Any amount is appreciated!