> ## Documentation Index
> Fetch the complete documentation index at: https://docs.biconomy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Build a Gasless Web3 App

> Step-by-step guide to building a gasless Web3 application. Learn how to implement gas sponsorship, paymasters, and frictionless onboarding for your dApp

# How to Build a Gasless Web3 App

<Accordion title="What do I need to build a gasless app?">
  Building a gasless Web3 app requires:

  | Component                 | Purpose                                                                       | Biconomy Solution                   |
  | ------------------------- | ----------------------------------------------------------------------------- | ----------------------------------- |
  | **Smart Account**         | Account abstraction enabled wallet                                            | Nexus Smart Account                 |
  | **Execution Environment** | Handles transaction orchestration, gas sponsorship, and cross-chain execution | MEE (Modular Execution Environment) |
  | **SDK**                   | Developer integration                                                         | AbstractJS SDK                      |

  <Note>
    Biconomy's MEE provides all the functionality of traditional ERC-4337 bundlers and paymasters in a unified, easier-to-use package. Instead of configuring separate bundler and paymaster services, MEE handles everything automatically.
  </Note>

  You'll also need:

  * A Biconomy dashboard account for API keys
  * A sponsorship policy (who/what to sponsor)
  * Frontend integration (React, Vue, vanilla JS, etc.)
</Accordion>

<Accordion title="How do I set up my project for gasless transactions?">
  **Step 1: Install dependencies**

  ```bash theme={null}
  npm install @biconomy/abstractjs viem
  ```

  **Step 2: Get API keys from Biconomy Dashboard**

  1. Go to [dashboard.biconomy.io](https://dashboard.biconomy.io)
  2. Create a new project
  3. Get your MEE API key
  4. Configure sponsorship policies

  **Step 3: Initialize the SDK with MEE**

  ```typescript theme={null}
  import { createMeeClient, toMultichainNexusAccount } from "@biconomy/abstractjs";
  import { privateKeyToAccount } from "viem/accounts";
  import { base } from "viem/chains";

  // Create multichain account
  const account = await toMultichainNexusAccount({
    signer: privateKeyToAccount("0x..."), // User's signer
    chains: [base]
  });

  // Create MEE client - handles all bundler and paymaster functionality
  const meeClient = await createMeeClient({ account });

  console.log("Smart Account Address:", account.address);
  ```

  <Note>
    MEE (Modular Execution Environment) replaces the need to configure separate bundlers and paymasters. It provides all ERC-4337 functionality plus cross-chain capabilities in a single, unified interface.
  </Note>
</Accordion>

<Accordion title="How do I send a gasless transaction?">
  Once configured, sending gasless transactions is simple with MEE:

  ```typescript theme={null}
  // The user pays NOTHING - gas is sponsored through MEE
  const quote = await meeClient.getQuote({
    instructions: [
      {
        calls: [{
          to: "0xRecipientAddress",
          value: 0n,
          data: "0x" // Or encoded function call
        }]
      }
    ],
    feeToken: { address: "sponsored" } // Gas sponsored
  });

  const { hash } = await meeClient.executeQuote({ quote });
  console.log("Transaction hash:", hash);
  ```

  **For contract interactions:**

  ```typescript theme={null}
  import { encodeFunctionData } from "viem";

  // Encode your contract call
  const data = encodeFunctionData({
    abi: yourContractABI,
    functionName: "mint",
    args: [userAddress, tokenId]
  });

  // Send gasless transaction via MEE
  const quote = await meeClient.getQuote({
    instructions: [
      {
        calls: [{ to: contractAddress, value: 0n, data }]
      }
    ],
    feeToken: { address: "sponsored" }
  });

  const { hash } = await meeClient.executeQuote({ quote });
  ```

  MEE automatically handles gas sponsorship based on your dashboard configuration.
</Accordion>

<Accordion title="How do I integrate with popular wallet connectors?">
  **With Privy (Recommended for embedded wallets):**

  ```typescript theme={null}
  import { usePrivy, useWallets } from "@privy-io/react-auth";
  import { createMeeClient, toMultichainNexusAccount } from "@biconomy/abstractjs";
  import { base } from "viem/chains";

  function App() {
    const { authenticated } = usePrivy();
    const { wallets } = useWallets();

    async function initMeeClient() {
      const wallet = wallets[0];
      const provider = await wallet.getEthereumProvider();
      
      const account = await toMultichainNexusAccount({
        signer: provider,
        chains: [base]
      });
      
      const meeClient = await createMeeClient({ account });
      return meeClient;
    }
  }
  ```

  **With RainbowKit/wagmi:**

  ```typescript theme={null}
  import { useWalletClient } from "wagmi";
  import { createMeeClient, toMultichainNexusAccount } from "@biconomy/abstractjs";
  import { base } from "viem/chains";

  function App() {
    const { data: walletClient } = useWalletClient();

    async function initMeeClient() {
      if (!walletClient) return;
      
      const account = await toMultichainNexusAccount({
        signer: walletClient,
        chains: [base]
      });
      
      const meeClient = await createMeeClient({ account });
      return meeClient;
    }
  }
  ```
</Accordion>

<Accordion title="How do I configure sponsorship policies?">
  Sponsorship policies control who and what gets sponsored. Configure in the Biconomy Dashboard:

  **Dashboard Configuration:**

  1. Navigate to MEE sponsorship settings
  2. Set spending limits (per transaction, total)

  <Note>
    MEE handles gas sponsorship (traditionally done by ERC-4337 paymasters) as part of its unified execution environment. You configure policies in the dashboard, and MEE applies them automatically.
  </Note>

  **Policy Examples:**

  *Sponsor all transactions (development):*

  ```json theme={null}
  {
    "mode": "SPONSORED",
    "policy": {
      "type": "open"
    }
  }
  ```

  *Sponsor with spending limits:*

  ```json theme={null}
  {
    "mode": "SPONSORED",
    "policy": {
      "type": "limited",
      "maxGasPerTransaction": "0.001",
      "maxTotalSpend": "10.0"
    }
  }
  ```
</Accordion>

<Accordion title="How do I handle the first-time user experience?">
  For first-time users, the smart account needs to be deployed. MEE handles this automatically:

  ```typescript theme={null}
  // First transaction deploys the account + executes the action
  // All in one gasless transaction via MEE!
  const quote = await meeClient.getQuote({
    instructions: [
      { calls: [{ to: contractAddress, data: mintCalldata }] }
    ],
    feeToken: { address: "sponsored" }
  });

  const { hash } = await meeClient.executeQuote({ quote });

  // User experience:
  // 1. User clicks "Mint NFT"
  // 2. Signs one message (no gas needed)
  // 3. Account deployed + NFT minted
  // 4. Done! ✅
  ```

  **Best practices for onboarding:**

  ```typescript theme={null}
  async function onboardUser(email: string) {
    // 1. Create wallet with embedded solution (Privy, Dynamic, etc.)
    const wallet = await createEmbeddedWallet(email);
    
    // 2. Initialize MEE client
    const account = await toMultichainNexusAccount({
      signer: wallet,
      chains: [base]
    });
    const meeClient = await createMeeClient({ account });
    
    // 3. Pre-compute address (no deployment yet)
    const address = account.address;
    
    // 4. First gasless transaction deploys account
    // Schedule this for user's first meaningful action
    
    return { wallet, meeClient, address };
  }
  ```
</Accordion>

<Accordion title="How do I batch multiple operations?">
  Batch operations save gas and improve UX with MEE:

  ```typescript theme={null}
  // Execute multiple operations in ONE gasless transaction via MEE
  const quote = await meeClient.getQuote({
    instructions: [
      {
        calls: [
          { to: tokenAddress, data: encodeApprove(spender, amount) },
          { to: vaultAddress, data: encodeDeposit(amount) },
          { to: rewardsAddress, data: encodeClaim() }
        ]
      }
    ],
    feeToken: { address: "sponsored" }
  });

  const { hash } = await meeClient.executeQuote({ quote });
  // User signs once, all three actions execute atomically
  ```

  **Real-world example - NFT mint with approval:**

  ```typescript theme={null}
  const quote = await meeClient.getQuote({
    instructions: [
      {
        calls: [
          // 1. Approve payment token
          {
            to: usdcAddress,
            data: encodeFunctionData({
              abi: erc20Abi,
              functionName: "approve",
              args: [nftContract, mintPrice]
            })
          },
          // 2. Mint NFT
          {
            to: nftContract,
            data: encodeFunctionData({
              abi: nftAbi,
              functionName: "mint",
              args: [quantity]
            })
          }
        ]
      }
    ],
    feeToken: { address: "sponsored" }
  });

  // One click, one signature, gasless!
  await meeClient.executeQuote({ quote });
  ```
</Accordion>

<Accordion title="How do I estimate and display costs?">
  Even for gasless transactions, showing users what's happening builds trust:

  ```typescript theme={null}
  // Get quote with cost estimate via MEE
  const quote = await meeClient.getQuote({
    instructions: [
      { calls: [{ to: contractAddress, data: calldata }] }
    ],
    feeToken: { address: "sponsored" }
  });

  // Quote includes cost breakdown
  console.log("Estimated cost:", quote.paymentInfo);
  // Display to user
  console.log(`Gas sponsored: $${quote.paymentInfo.usdCost.toFixed(2)}`);
  // "Gas sponsored: $0.45"
  ```

  **UI Example:**

  ```tsx theme={null}
  function TransactionButton({ onSubmit }) {
    const [sponsoredAmount, setSponsoredAmount] = useState(null);
    
    return (
      <button onClick={onSubmit}>
        Mint NFT
        {sponsoredAmount && (
          <span className="sponsored-badge">
            Gas sponsored: ${sponsoredAmount}
          </span>
        )}
      </button>
    );
  }
  ```
</Accordion>

<Accordion title="How do I handle errors gracefully?">
  Common errors and how to handle them:

  ```typescript theme={null}
  try {
    const quote = await meeClient.getQuote({
      instructions: [{ calls: [{ to: contractAddress, data: calldata }] }],
      feeToken: { address: "sponsored" }
    });
    const { hash } = await meeClient.executeQuote({ quote });
  } catch (error) {
    if (error.message.includes("sponsorship denied")) {
      // User exceeded sponsorship limits
      showMessage("Daily free transactions exceeded. Please try again tomorrow.");
    } else if (error.message.includes("insufficient balance")) {
      // Contract requires token balance
      showMessage("Insufficient token balance for this action.");
    } else if (error.message.includes("user rejected")) {
      // User cancelled signature
      showMessage("Transaction cancelled.");
    } else {
      // Generic error
      showMessage("Transaction failed. Please try again.");
      console.error(error);
    }
  }
  ```

  **Implement retry logic:**

  ```typescript theme={null}
  async function sendWithRetry(instructions, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
      try {
        const quote = await meeClient.getQuote({
          instructions,
          feeToken: { address: "sponsored" }
        });
        return await meeClient.executeQuote({ quote });
      } catch (error) {
        if (i === maxRetries - 1) throw error;
        await new Promise(r => setTimeout(r, 1000 * (i + 1)));
      }
    }
  }
  ```
</Accordion>

<Accordion title="What's a complete example of a gasless app?">
  Here's a complete gasless NFT minting app using MEE:

  ```typescript theme={null}
  // lib/biconomy.ts
  import { createMeeClient, toMultichainNexusAccount } from "@biconomy/abstractjs";
  import { base } from "viem/chains";

  export async function createGaslessMeeClient(signer: any) {
    const account = await toMultichainNexusAccount({
      signer,
      chains: [base]
    });
    
    return createMeeClient({ account });
  }
  ```

  ```tsx theme={null}
  // components/MintButton.tsx
  import { useState } from "react";
  import { createGaslessMeeClient } from "@/lib/biconomy";
  import { encodeFunctionData } from "viem";
  import { nftAbi, NFT_ADDRESS } from "@/lib/contracts";

  export function MintButton({ signer }) {
    const [loading, setLoading] = useState(false);
    const [txHash, setTxHash] = useState(null);

    async function handleMint() {
      setLoading(true);
      try {
        // Initialize MEE client
        const meeClient = await createGaslessMeeClient(signer);
        
        // Encode mint function
        const data = encodeFunctionData({
          abi: nftAbi,
          functionName: "mint",
          args: [1] // Mint 1 NFT
        });
        
        // Get quote and execute gasless transaction via MEE
        const quote = await meeClient.getQuote({
          instructions: [
            { calls: [{ to: NFT_ADDRESS, data, value: 0n }] }
          ],
          feeToken: { address: "sponsored" }
        });
        
        const { hash } = await meeClient.executeQuote({ quote });
        setTxHash(hash);
      } catch (error) {
        console.error("Mint failed:", error);
        alert("Minting failed. Please try again.");
      } finally {
        setLoading(false);
      }
    }

    return (
      <div>
        <button onClick={handleMint} disabled={loading}>
          {loading ? "Minting..." : "Mint NFT (Free!)"}
        </button>
        {txHash && (
          <p>
            Success! <a href={`https://basescan.org/tx/${txHash}`}>View transaction</a>
          </p>
        )}
      </div>
    );
  }
  ```

  <Note>
    MEE provides all the functionality of traditional ERC-4337 bundlers and paymasters in a single, unified interface. No need to configure separate bundler URLs or paymaster URLs.
  </Note>
</Accordion>

***

## Continue building

<CardGroup cols={2}>
  <Card title="ERC-4337 Paymaster" icon="credit-card" href="/faq/erc-4337-paymaster">
    Deep dive into paymaster configuration
  </Card>

  <Card title="Batched Transactions" icon="layer-group" href="/faq/batched-transactions-evm">
    Combine multiple operations efficiently
  </Card>
</CardGroup>
