How to Add a Gasless Transaction Button to Your Next.js dApp
Step-by-step tutorial to implement gasless transactions using ERC-4337 account abstraction in your Next.js application. Complete code examples with GasX integration.
How to Add a Gasless Transaction Button to Your Next.js dApp
Gas fees are the #1 barrier to Web3 adoption. New users abandon transactions when they see they need ETH just to interact with your dApp. This tutorial shows you how to eliminate that friction with gasless transactions.
What You'll Build
By the end of this tutorial, you'll have a working "Gasless Mint" button that:
- Lets users mint NFTs without paying gas
- Works with any ERC-4337 compatible wallet
- Integrates with GasX for gas sponsorship
Prerequisites
- Next.js 14+ project with App Router
- Basic understanding of React hooks
- A GasX account (free tier available)
Step 1: Install Dependencies
First, install the required packages:
pnpm add wagmi viem @tanstack/react-query permissionless
These packages provide:
- wagmi: React hooks for Ethereum
- viem: TypeScript Ethereum library
- permissionless: ERC-4337 account abstraction utilities
Step 2: Configure Your Providers
Create a providers file to set up wagmi with account abstraction support:
// app/providers.tsx
'use client';
import { WagmiProvider, createConfig, http } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { arbitrum, optimism, base } from 'wagmi/chains';
const config = createConfig({
chains: [arbitrum, optimism, base],
transports: {
[arbitrum.id]: http(),
[optimism.id]: http(),
[base.id]: http(),
},
});
const queryClient = new QueryClient();
export function Providers({ children }: { children: React.ReactNode }) {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</WagmiProvider>
);
}
Step 3: Create the Gasless Transaction Hook
This is where the magic happens. Create a custom hook that handles gasless transactions:
// hooks/useGaslessTransaction.ts
'use client';
import { useState } from 'react';
import { encodeFunctionData, type Hex } from 'viem';
import { useAccount } from 'wagmi';
interface GaslessTransactionParams {
to: Hex;
data: Hex;
value?: bigint;
}
export function useGaslessTransaction() {
const { address } = useAccount();
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState<Error | null>(null);
const sendGaslessTransaction = async (params: GaslessTransactionParams) => {
if (!address) {
throw new Error('Wallet not connected');
}
setIsPending(true);
setError(null);
try {
// Call GasX API to sponsor the transaction
const response = await fetch('/api/sponsor', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: address,
target: params.to,
callData: params.data,
value: params.value?.toString() || '0',
}),
});
if (!response.ok) {
throw new Error('Sponsorship request failed');
}
const { userOpHash } = await response.json();
return userOpHash;
} catch (err) {
setError(err instanceof Error ? err : new Error('Unknown error'));
throw err;
} finally {
setIsPending(false);
}
};
return {
sendGaslessTransaction,
isPending,
error,
};
}
Step 4: Build the Gasless Button Component
Now create a reusable button component:
// components/GaslessButton.tsx
'use client';
import { useState } from 'react';
import { encodeFunctionData } from 'viem';
import { useGaslessTransaction } from '@/hooks/useGaslessTransaction';
import { Button } from '@/components/ui/button';
const NFT_CONTRACT = '0x...'; // Your NFT contract address
const NFT_ABI = [
{
name: 'mint',
type: 'function',
inputs: [{ name: 'to', type: 'address' }],
outputs: [],
},
] as const;
export function GaslessMintButton() {
const { sendGaslessTransaction, isPending } = useGaslessTransaction();
const [txHash, setTxHash] = useState<string | null>(null);
const handleMint = async () => {
const data = encodeFunctionData({
abi: NFT_ABI,
functionName: 'mint',
args: ['0x...'], // User's address
});
const hash = await sendGaslessTransaction({
to: NFT_CONTRACT,
data,
});
setTxHash(hash);
};
return (
<div>
<Button onClick={handleMint} disabled={isPending}>
{isPending ? 'Minting...' : 'Mint NFT (Gasless)'}
</Button>
{txHash && (
<p className="text-sm text-muted-foreground mt-2">
Transaction: {txHash}
</p>
)}
</div>
);
}
Step 5: Set Up the API Route
Create an API route to handle sponsorship requests:
// app/api/sponsor/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const body = await request.json();
// Call GasX API to create sponsored UserOperation
const response = await fetch('https://api.gasx.io/v1/sponsor', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.GASX_API_KEY}`,
},
body: JSON.stringify({
campaignId: process.env.GASX_CAMPAIGN_ID,
...body,
}),
});
const data = await response.json();
return NextResponse.json(data);
}
Step 6: Configure GasX Campaign
- Go to GasX Dashboard
- Create a new campaign
- Set your gas budget and eligible contracts
- Copy your Campaign ID and API Key
- Add them to your
.env.local:
GASX_API_KEY=your_api_key_here
GASX_CAMPAIGN_ID=your_campaign_id_here
Testing Your Integration
Run your development server:
pnpm dev
Try clicking the "Mint NFT (Gasless)" button. The transaction should go through without the user paying any gas!
Best Practices
1. Rate Limiting
Implement rate limiting to prevent abuse:
// Use a rate limiter like upstash/ratelimit
import { Ratelimit } from '@upstash/ratelimit';
2. Allowlist Contracts
Only sponsor transactions to known contracts to prevent exploitation.
3. Set Budget Caps
Configure daily and per-user limits in your GasX campaign settings.
4. Monitor Usage
Use the GasX analytics dashboard to track spending and identify patterns.
Common Issues
"Sponsorship request failed"
- Check your API key is valid
- Verify the contract is allowlisted
- Ensure your campaign has remaining budget
"Wallet not connected"
- Make sure the user has connected their wallet before calling the function
Next Steps
- Add transaction status tracking with webhooks
- Implement multi-chain support
- Create a custom paymaster for advanced use cases
Conclusion
Gasless transactions dramatically improve user experience in Web3. With GasX and ERC-4337, you can sponsor gas fees for your users with just a few lines of code.
Ready to go live? Create your GasX campaign now and start onboarding users without the gas fee friction.
Ready to eliminate gas friction?
Create your first gas sponsorship campaign in under 5 minutes. No coding required.
Create Campaign