Skip to main content

How to Implement Base Paymaster into a Wagmi Project

In this tutorial, we’ll create a Mint button that allows users to mint an NFT for free through transaction sponsorship from a Base Paymaster. This setup enables users to mint NFTs directly to their wallets without incurring gas fees. By the end, you’ll have a fully functional NFT minting setup with transaction sponsorship via the Base Paymaster. Let's build!

Objectives

  • Configure Wagmi for the Base Network
    Set up your Wagmi project to seamlessly interact with the Base blockchain, allowing users to connect their wallets and initiate transactions with ease.

  • Define Essential Constants
    Learn how to manage key information such as contract ABIs and addresses, which are crucial for interacting with smart contracts in your application.

  • Implement Paymaster-Sponsored NFT Minting
    Update onchain actions using Wagmi's writeContracts and useCalls hooks to enable gas-free NFT minting, allowing users to mint directly to their wallets without incurring transaction fees.

  • Enhance User Experience with Gasless Transactions
    Create a user-friendly experience by abstracting away the concept of gas fees, making it easier for users to engage with your application and mint NFTs.

Prerequisites

Wallet Connect Project ID

You’ll need to set up a cloud account with [Reown] (FKA, WalletConnect), a protocol that enables secure wallet connections across different platforms.

Base Paymaster + Bundler Endpoint

You'll need to set up an account (free) with the Coinbase Developer Platform (CDP) to obtain a Paymaster + Bundler endpoint, which is required for this tutorial. The CDP provides these essential services that enable transaction sponsorship.

Smart Wallet

Smart Wallets enables users to create an account in seconds with no app or extension required through the use of Passskey signing. This tutorial uses the Base Wallet (FKA Coinbase Smart Wallet) to sign and mint transactions.


Set Up Your Project

Create a New Wagmi Project

Start by creating a new Wagmi project with Bun:

bun create wagmi

Add WalletConnect Project ID

Add your WalletConnect Project ID to the .env file to enable wallet connection in the app. Open the .env file and add the following lines:

NEXT_PUBLIC_WC_PROJECT_ID=<YOUR_PROJECT_ID>
NEXT_TELEMETRY_DISABLED=1

Replace<YOUR_PROJECT_ID> with your actual WalletConnect Project ID.

Update Wagmi Configuration

Configure Wagmi for Base Network To integrate the Base network with Wagmi, update wagmi.ts as follows:

import { http, cookieStorage, createConfig, createStorage } from 'wagmi';
import { base } from 'wagmi/chains';
import { coinbaseWallet, injected, walletConnect } from 'wagmi/connectors';

export function getConfig() {
return createConfig({
chains: [base],
connectors: [
injected(),
coinbaseWallet(),
walletConnect({ projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID }),
],
storage: createStorage({
storage: cookieStorage,
}),
ssr: true,
transports: {
[base.id]: http(),
},
});
}

declare module 'wagmi' {
interface Register {
config: ReturnType<typeof getConfig>;
}
}

This configuration sets up your project to connect to the Base network and supports multiple connectors, including WalletConnect.

Create utils.ts for Contract ABI and Address

Create a new file utils.ts in the src folder. This file will store the contract’s ABI and address.

src/utils.ts

// utils.js

import { Abi } from 'viem';

export const contractAddress = '0x83bd615eb93ee1336aca53e185b03b54ff4a17e8' as `0x${string}`;

export const abi = [
{
type: 'constructor',
inputs: [
{ name: '_name', type: 'string', internalType: 'string' },
{ name: '_symbol', type: 'string', internalType: 'string' },
],
stateMutability: 'nonpayable',
},
// ABI code here
] as Abi;

Replace the contract address and ABI as per your contract’s details.

Create the NFT Minting Page

In this step, we’ll create a new page in our project where users can mint an NFT. The minting page will use Wagmi’s hooks, including useCapabilities to check the capabilities supported by the connected wallet and useWriteContracts to execute a mint function on our smart contract.

Set Up mint/page.tsx

In your project’s src/app folder, create a new file called mint/page.tsx. This file will contain the code to manage wallet connection, check for paymaster capabilities, and execute the minting action.

Experimenal Hooks and Capabilities

To ensure a smooth, gas-free NFT minting experience, it’s important to understand the purpose of two key hooks from Wagmi:

  • useCapabilities: This hook retrieves the list of capabilities (such as paymasterService) supported by the connected wallet, grouped by chain ID. This is crucial because we need to confirm that the connected wallet supports paymaster sponsorship, which allows transactions to be sponsored by a third party (in this case, Base Paymaster).

  • useWriteContracts: This hook allows us to interact with smart contracts on the blockchain. Specifically, we’ll use it to trigger the mintTo function, which will mint an NFT to the user’s wallet.

By combining these hooks, we can detect whether the user’s wallet is capable of sponsored transactions and, if so, use the writeContracts function to mint an NFT without charging the user any gas fees.

Add the Code for NFT Minting

For Wallet Connection: We use useAccount, useConnect, and useDisconnect to manage wallet connection. This allows users to connect via Coinbase Smart Wallet and disconnect as needed.


'use client';
import { useAccount, useConnect, useDisconnect } from 'wagmi';
import { useState, useMemo } from 'react';
import { coinbaseWallet } from 'wagmi/connectors';
import { abi, contractAddress } from '../utils';
import { useCapabilities, useWriteContracts } from 'wagmi/experimental';

export default function Home() {
const { address, isConnected } = useAccount();
const { connect } = useConnect();
const { disconnect } = useDisconnect();
const [isMinting, setIsMinting] = useState(false);
const [id, setId] = useState<string | undefined>(undefined);

// Follow along for more code ...

Capabilities Check with useCapabilities: Using useCapabilities, we retrieve the wallet’s supported capabilities, grouped by chain ID. In this example, we’re checking if the wallet has the paymasterService capability, which indicates it can use a Base Paymaster for gas-free transactions. If paymaster service is supported, we configure the capabilities object to include the Base Paymaster URL.

// Retrieve wallet capabilities to check for paymaster support
const { data: availableCapabilities } = useCapabilities({
account: address,
});
const capabilities = useMemo(() => {
if (!availableCapabilities || !address) return {};
const capabilitiesForChain = availableCapabilities[address.chainId];
if (
capabilitiesForChain['paymasterService'] &&
capabilitiesForChain['paymasterService'].supported
) {
return {
paymasterService: {
url: `https://api.developer.coinbase.com/rpc/v1/base/rcNfIncd3jL3FztkZ7TPOV_sfHUGlcVP`,
},
};
}
return {};
}, [availableCapabilities, address]);

Minting Logic with useWriteContracts: We use useWriteContracts to interact with the smart contract and call the mintTo function, which mints the NFT. By passing capabilities, the transaction is sponsored by the Base Paymaster, covering gas fees for the user.

The Mint button will either prompt the user to connect their wallet (if not connected), or execute the handleMint function to mint an NFT (if connected). During the minting process, the button shows “Minting…” to indicate the ongoing transaction.

The full src/app/mint/page.tsx file should look something like this:

Smart Wallet Only

To enable Base Wallet functionality add the smartWalletOnly prefence to the wagmi connector

<button
onClick={
isConnected
? handleMint
: () =>
connect({
connector: coinbaseWallet({
preference: 'smartWalletOnly',
}),
})
}
className='bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded'
disabled={isMinting}
>
'use client';
import { useAccount, useConnect, useDisconnect } from 'wagmi';
import { useState, useMemo } from 'react';
import { coinbaseWallet } from 'wagmi/connectors';
import { abi, contractAddress } from '../utils';
import { useCapabilities, useWriteContracts } from 'wagmi/experimental';

export default function Home() {
const { address, isConnected } = useAccount();
const { connect } = useConnect();
const { disconnect } = useDisconnect();
const [isMinting, setIsMinting] = useState(false);
const [id, setId] = useState<string | undefined>(undefined);

// Use writeContracts to execute the mint function on our contract
const { writeContracts } = useWriteContracts({
mutation: { onSuccess: (id) => setId(id) },
});

// Function to handle the minting process
const handleMint = async () => {
setIsMinting(true);
try {
console.log('Minting NFT...');
writeContracts({
contracts: [
{
address: contractAddress,
abi,
functionName: 'mintTo',
args: [address],
},
],
capabilities,
});
} catch (error) {
console.error('Error minting NFT:', error);
} finally {
setIsMinting(false);
}
};

// Retrieve wallet capabilities to check for paymaster support
const { data: availableCapabilities } = useCapabilities({
account: address,
});
const capabilities = useMemo(() => {
if (!availableCapabilities || !address) return {};
const capabilitiesForChain = availableCapabilities[address.chainId];
if (
capabilitiesForChain['paymasterService'] &&
capabilitiesForChain['paymasterService'].supported
) {
return {
paymasterService: {
url: `https://api.developer.coinbase.com/rpc/v1/base/rcNfIncd3jL3FztkZ7TPOV_sfHUGlcVP`,
},
};
}
return {};
}, [availableCapabilities, address]);

return (
<div className="flex min-h-screen items-center justify-center">
<div>
<h1>Connected Wallet: </h1>
<p>{address ? address : 'No wallet detected'}</p>
</div>
<div>
{isConnected && (
<button type="button" onClick={() => disconnect()}>
Disconnect
</button>
)}
</div>
<button
onClick={
isConnected
? handleMint
: () =>
connect({
connector: coinbaseWallet({
preference: 'smartWalletOnly',
}),
})
}
className="rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"
disabled={isMinting}
>
{isMinting ? 'Minting...' : isConnected ? 'Mint NFT' : 'Connect Wallet'}
</button>
</div>
);
}

This component detects if a wallet is connected, then allows users to mint an NFT. If no wallet is detected, it prompts the user to connect via the Coinbase Smart Wallet.

Testing

Start your development server to test the minting functionality:

bun run dev

Open your browser and navigate to your site’s local URL:


http://localhost:3000/mint

image-of-server

Connect Your Wallet and Mint Once on the mint page, connect your wallet. You should see a Mint button appear. Upon clicking the Mint button, a smart wallet popup will prompt you to confirm the mint transaction.

image-of-mint-modal

Verify Your NFT

After minting, you can verify the NFT in your Base Wallet:

Go to Coinbase Wallet.

Navigate to the Assets section and select the NFT tab.

smart-wallet-home

You should see your newly minted NFT in your collection.

smart-wallet-assets

Conclusion

Congratulations! You’ve successfully integrated a Base Paymaster to enable gas-free NFT minting within your Wagmi project. By configuring your project with Base network support, defining contract details, and using Wagmi hooks for minting, you’ve created a user-friendly, gasless minting experience. Now your users can mint NFTs without transaction costs, enhancing both accessibility and engagement with your app.

Happy building!


We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking . For more information see our Cookie Policy.