<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Base West Africa]]></title><description><![CDATA[Base West Africa]]></description><link>https://blog.basewestafrica.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 11:32:25 GMT</lastBuildDate><atom:link href="https://blog.basewestafrica.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Guide to Paying Gas for Users with Base Paymaster]]></title><description><![CDATA[This guide shows you how to sponsor transaction fees for users with Base Paymaster, making your dApp more user-friendly.
When interacting with a blockchain, users are required to pay transaction (gas) fees. While these fees are typically low on Base,...]]></description><link>https://blog.basewestafrica.com/guide-to-paying-gas-for-users-with-base-paymaster</link><guid isPermaLink="true">https://blog.basewestafrica.com/guide-to-paying-gas-for-users-with-base-paymaster</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[gasless]]></category><category><![CDATA[account abstraction]]></category><category><![CDATA[ERC-4337]]></category><dc:creator><![CDATA[Ogedengbe Israel]]></dc:creator><pubDate>Sun, 06 Jul 2025 13:46:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751809582657/45b31213-5ac7-4ce6-8f62-2497491fb315.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This guide shows you how to sponsor transaction fees for users with Base Paymaster, making your dApp more user-friendly.</p>
<p>When interacting with a blockchain, users are required to pay transaction (gas) fees. While these fees are typically low on Base, often less than $0.01, they can still be confusing or intimidating, especially for non-Web3-native users. Requiring users to fund a wallet before engaging with your app can create friction and negatively impact the user experience (UX). Paymaster allows you to sponsor up to $15k monthly on mainnet (unlimited on testnet). Get Gas Fees Covered. <a target="_blank" href="https://forms.gle/7ggCftfeNsJuvwUJA">Apply Now</a></p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>To follow this tutorial, you should already have:</p>
<ol>
<li><p><strong>A Coinbase Cloud Developer Platform (CDP) Account</strong></p>
<p> If you have not, sign up on the <a target="_blank" href="https://portal.cdp.coinbase.com">CDP Portal</a>. After signing up, you can manage projects and utilize different tools like the paymaster.</p>
</li>
<li><p><strong>A basic understanding of Smart Accounts and how ERC-4337 works</strong></p>
<p> Smart Accounts are the foundation of advanced transaction flows like gas sponsorship and transaction batching. This tutorial builds on the ERC-4337 account abstraction standard, so if you’re unfamiliar with it, we recommend checking out resources like the official EIP-4337 explainer <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4337">before getting started.</a></p>
</li>
<li><p><strong>Foundry</strong></p>
<p> Foundry is a development environment, testing framework, and smart contract toolkit for Ethereum. You’ll need it installed locally for generating key pairs and interacting with smart contracts.</p>
</li>
</ol>
<h3 id="heading-set-up-gas-sponsorship-with-base-paymaster">Set Up Gas Sponsorship with Base Paymaster</h3>
<p>This section walks you through setting up gas sponsorship using Base Paymaster. You’ll configure your project to sponsor transactions on behalf of users by interacting with the Paymaster and bundler services provided by the Coinbase Developer Platform.</p>
<ol>
<li><p>Go to the <a target="_blank" href="https://portal.cdp.coinbase.com/">Coinbase Developer Platform</a>.</p>
</li>
<li><p>Create or select your project from the upper-left corner.</p>
</li>
<li><p>From the left-hand menu, hover on “Base Tools” and click “Paymaster”</p>
</li>
<li><p>Navigate to the configuration tab and copy the RPC_URL, you’ll use it in your code to connect to the bundler and paymaster Services.</p>
</li>
</ol>
<h3 id="heading-screenshots"><strong>Screenshots</strong></h3>
<ol>
<li><p>Selecting your project</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751803878761/7406849b-9d65-4602-80a7-57cf2128ad71.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Navigate to base tools &gt; paymaster</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751804039489/edd08ca1-010c-4eed-8a37-3d8bdf296e07.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Configuration screen</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751804256823/21fafade-bb7c-4704-895c-56fe7da1a0ff.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h3 id="heading-allowlist-a-contract-for-sponsorship">Allowlist a Contract for Sponsorship</h3>
<ol>
<li><p>On the configuration page, make sure Base Mainnet is selected. Select Base Sepolia if you’re testing (testnet)</p>
</li>
<li><p>Turn on your Paymaster by toggling the <strong><em>Enable Paymaster</em></strong> switch</p>
</li>
<li><p>Click “Add” to allowlist a contract that can receive sponsored transactions</p>
</li>
<li><p>For this example, use the</p>
<p> contract name: <code>DemoNFT</code></p>
<p> contract address:<code>0xd33bb1C4c438600db4611bD144fDF5048f6C8E44</code><br /> Then add the function you want to sponsor: <code>mintTo(address)</code>.</p>
</li>
</ol>
<blockquote>
<p>This ensures your Paymaster only covers gas fees for specific functions you approve — in this case, the <code>mintTo</code> function on the <code>DemoNFT</code> contract.<br /><strong>Note:</strong> If you leave the function input box empty, the Paymaster will sponsor <strong>all functions</strong> on the contract, so use this with caution.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751804908911/af34d485-5285-4886-9ba0-e0a8771b5011.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Note: The contract name, address, and function above are from our example NFT contract on Base Mainnet. You should replace them with the details of your own contract.</p>
</blockquote>
<h3 id="heading-global-amp-per-user-limits">Global &amp; Per User Limits</h3>
<p>Scroll to <strong>Per User Limit</strong> to set:</p>
<ul>
<li><p>Max USD (e.g., $0.05)</p>
</li>
<li><p>Max UserOperations (e.g., 1)</p>
</li>
<li><p>Reset cycle (daily, weekly, or monthly)</p>
</li>
</ul>
<p>This means each user gets $0.05 and 1 sponsored transaction per cycle.</p>
<p>Then set the <strong>Global Limit</strong> (e.g., $0.07). Once reached, no more sponsorships happen until the limit is increased.</p>
<h3 id="heading-implementing-gas-sponsorship-on-the-backend">Implementing Gas Sponsorship on the Backend</h3>
<p><strong>Installing</strong> <strong>Foundry</strong></p>
<ol>
<li><p>Ensure you have Rust installed</p>
<pre><code class="lang-plaintext"> curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
</code></pre>
</li>
<li><p>Install Foundry</p>
<pre><code class="lang-plaintext"> curl -L https://foundry.paradigm.xyz | bash
 foundryup
</code></pre>
</li>
<li><p>Verify it works</p>
<pre><code class="lang-plaintext"> cast --help
</code></pre>
<p> You should see Foundry usage information <strong>voilà</strong>, you’re good to go!</p>
</li>
</ol>
<h3 id="heading-create-your-project-and-generate-key-pairs">Create Your Project and Generate Key Pairs</h3>
<ol>
<li><p>Create a folder and install dependencies, viem and dotenv:</p>
<pre><code class="lang-plaintext"> mkdir viem-gasless
 cd viem-gasless
 npm install viem
 npm install dotenv
 touch config.js
 touch index.js
 touch example-app-abi.js
</code></pre>
</li>
<li><p>Generate a key pair with foundry</p>
<pre><code class="lang-plaintext"> cast wallet new
</code></pre>
</li>
<li><p>You’ll see something like:</p>
<pre><code class="lang-plaintext"> Successfully created new keypair.
 Address:     0xa05Ed6858568cbc14cfEd559C068E02e95521De4
 Private key: 0xf920002d619ca04287848a9...
</code></pre>
<p> <strong>Store these private keys safe</strong></p>
</li>
</ol>
<p>Create a <code>.env</code> file in the <code>viem-gasless</code> folder. In the <code>.env</code>, you’ll add the rpcURL for your paymaster and the private key for your account. The rpcURL can be found from the CDP Portal, it follows the pattern <a target="_blank" href="https://api.developer.coinbase.com/rpc/v1/base/&lt;SPECIAL-KEY&gt;Navigate"><code>https://api.developer.coinbase.com/rpc/v1/base/&lt;SPECIAL-KEY&gt;</code></a>. That way our <code>.env</code> would look like this:</p>
<pre><code class="lang-plaintext">RPC_URL=https://api.developer.coinbase.com/rpc/v1/base/&lt;SPECIAL-KEY&gt;
OWNER_PRIVATE_KEY=0xf920002d619ca04287848a9...
</code></pre>
<blockquote>
<p><code>.env</code> should not be committed to a public repo. Do not forget to add it to <code>.gitignore</code></p>
</blockquote>
<h3 id="heading-example-configjs">Example <code>config.js</code></h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createPublicClient, http } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem"</span>;
<span class="hljs-keyword">import</span> { toCoinbaseSmartAccount } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem/account-abstraction"</span>;
<span class="hljs-keyword">import</span> { privateKeyToAccount } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem/accounts"</span>;
<span class="hljs-keyword">import</span> { base } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem/chains"</span>;
<span class="hljs-keyword">import</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">'dotenv'</span>;

<span class="hljs-comment">// Load environment variables from .env file</span>
dotenv.config();

<span class="hljs-keyword">const</span> RPC_URL = process.env.RPC_URL;
<span class="hljs-keyword">const</span> OWNER_PRIVATE_KEY = process.env.OWNER_PRIVATE_KEY;

<span class="hljs-keyword">if</span> (!RPC_URL) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'RPC_URL is not set in environment variables'</span>);
}

<span class="hljs-keyword">if</span> (!OWNER_PRIVATE_KEY) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'OWNER_PRIVATE_KEY is not set in environment variables'</span>);
}

<span class="hljs-keyword">export</span> { RPC_URL };

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> client = createPublicClient({
    <span class="hljs-attr">chain</span>: base,
    <span class="hljs-attr">transport</span>: http(RPC_URL),
});

<span class="hljs-keyword">const</span> owner = privateKeyToAccount(OWNER_PRIVATE_KEY);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> account = <span class="hljs-keyword">await</span> toCoinbaseSmartAccount({
    client,
    <span class="hljs-attr">owners</span>: [owner],
});
</code></pre>
<p><code>example-app-abi-.js</code>  </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> abi = [
  {
    <span class="hljs-attr">inputs</span>: [
      {
        <span class="hljs-attr">internalType</span>: <span class="hljs-string">"address"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"to"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"address"</span>,
      },
    ],
    <span class="hljs-attr">name</span>: <span class="hljs-string">"mintTo"</span>,
    <span class="hljs-attr">outputs</span>: [
      {
        <span class="hljs-attr">internalType</span>: <span class="hljs-string">"uint256"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"uint256"</span>,
      },
    ],
    <span class="hljs-attr">stateMutability</span>: <span class="hljs-string">"nonpayable"</span>,
    <span class="hljs-attr">type</span>: <span class="hljs-string">"function"</span>,
  },
  {
    <span class="hljs-attr">inputs</span>: [
      {
        <span class="hljs-attr">internalType</span>: <span class="hljs-string">"address"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"owner"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"address"</span>,
      },
    ],
    <span class="hljs-attr">name</span>: <span class="hljs-string">"balanceOf"</span>,
    <span class="hljs-attr">outputs</span>: [
      {
        <span class="hljs-attr">internalType</span>: <span class="hljs-string">"uint256"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"uint256"</span>,
      },
    ],
    <span class="hljs-attr">stateMutability</span>: <span class="hljs-string">"view"</span>,
    <span class="hljs-attr">type</span>: <span class="hljs-string">"function"</span>,
  },
];
</code></pre>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { http } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem"</span>;
<span class="hljs-keyword">import</span> { base } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem/chains"</span>;
<span class="hljs-keyword">import</span> { createBundlerClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem/account-abstraction"</span>;
<span class="hljs-keyword">import</span> { account, client, RPC_URL } <span class="hljs-keyword">from</span> <span class="hljs-string">"./config.js"</span>;
<span class="hljs-keyword">import</span> { abi } <span class="hljs-keyword">from</span> <span class="hljs-string">"./example-app-abi.js"</span>;

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"🚀 Starting gasless NFT minting process..."</span>);

<span class="hljs-keyword">const</span> bundlerClient = createBundlerClient({
  account,
  client,
  <span class="hljs-attr">transport</span>: http(RPC_URL),
  <span class="hljs-attr">chain</span>: base,
});

<span class="hljs-keyword">const</span> nftContractAddress = <span class="hljs-string">"0xd33bb1C4c438600db4611bD144fDF5048f6C8E44"</span>; <span class="hljs-comment">// DEMO NFT Contract Deployed on Mainnet (base)</span>

<span class="hljs-keyword">const</span> mintTo = {
  <span class="hljs-attr">abi</span>: abi,
  <span class="hljs-attr">functionName</span>: <span class="hljs-string">"mintTo"</span>,
  <span class="hljs-attr">to</span>: nftContractAddress,
  <span class="hljs-attr">args</span>: [account.address],
};
<span class="hljs-keyword">const</span> calls = [mintTo];

account.userOperation = {
  <span class="hljs-attr">estimateGas</span>: <span class="hljs-keyword">async</span> (userOperation) =&gt; {
    <span class="hljs-keyword">const</span> estimate = <span class="hljs-keyword">await</span> bundlerClient.estimateUserOperationGas(
      userOperation
    );
    estimate.preVerificationGas = estimate.preVerificationGas * <span class="hljs-number">2n</span>;
    <span class="hljs-keyword">return</span> estimate;
  },
};

<span class="hljs-keyword">try</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"📤 Sending user operation..."</span>);

  <span class="hljs-keyword">const</span> userOpHash = <span class="hljs-keyword">await</span> bundlerClient.sendUserOperation({
    account,
    calls,
    <span class="hljs-attr">paymaster</span>: <span class="hljs-literal">true</span>,
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"⏳ Waiting for transaction receipt..."</span>);

  <span class="hljs-keyword">const</span> receipt = <span class="hljs-keyword">await</span> bundlerClient.waitForUserOperationReceipt({
    <span class="hljs-attr">hash</span>: userOpHash,
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"✅ Transaction successfully sponsored"</span>);
  <span class="hljs-built_in">console</span>.log(
    <span class="hljs-string">`⛽ View sponsored UserOperation on blockscout: https://base.blockscout.com/op/<span class="hljs-subst">${receipt.userOpHash}</span>`</span>
  );
  process.exit(<span class="hljs-number">0</span>);
} <span class="hljs-keyword">catch</span> (error) {
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"❌ Error sending transaction: "</span>, error);
  process.exit(<span class="hljs-number">1</span>);
}
</code></pre>
<p>Now that the code is implemented, lets run it: Run this via <code>node index.js</code> from your project root.</p>
<pre><code class="lang-plaintext">node index.js
</code></pre>
<p>To test if your spend policy is working, set it to allow just <strong>1 transaction per user</strong>. When you run the script again, you should get a <strong>"request denied"</strong> error — that means it’s working!</p>
<p>Want to see full examples? We’ve got setups for <strong>Wagmi + Vite</strong>, <strong>Wagmi + Next.js</strong>, and even <strong>server-side integration</strong>.<br />Check them out on <a target="_blank" href="https://github.com/Base-West-Africa/Demo-examples">GitHub</a></p>
]]></content:encoded></item><item><title><![CDATA[Smart Wallets on Base: A Developer’s Guide to Better Onchain UX]]></title><description><![CDATA[What is a Smart Wallet?
A smart wallet is a non-custodial crypto wallet powered by smart contracts on the blockchain. It makes it possible for your users to create an onchain account in seconds, without any app or extension. One of the best and most ...]]></description><link>https://blog.basewestafrica.com/smart-wallets-on-base-a-developers-guide-to-better-onchain-ux</link><guid isPermaLink="true">https://blog.basewestafrica.com/smart-wallets-on-base-a-developers-guide-to-better-onchain-ux</guid><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[account abstraction]]></category><category><![CDATA[base]]></category><dc:creator><![CDATA[Ogedengbe Israel]]></dc:creator><pubDate>Mon, 23 Jun 2025 12:38:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750682192710/d46f91fc-887b-4e19-839b-d30d421273a3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-a-smart-wallet">What is a Smart Wallet?</h2>
<p>A smart wallet is a non-custodial crypto wallet powered by smart contracts on the blockchain. It makes it possible for your users to create an onchain account in seconds, without any app or extension. One of the best and most friendly ways to enable users to interact with onchain applications.</p>
<h2 id="heading-how-does-smart-wallet-work">How Does Smart Wallet Work?</h2>
<p>Smart wallets rely on passkeys, stored on users’ devices which can be used on the Coinbase website (keys.coinbase.com) and mobile app. Developers get to integrate an SDK that uses keys.coinbase.com popups to allow users to see requests and sign with their passkey. The SDK and the popup use cross-domain messaging to share information back to the app.</p>
<p>Coinbase SDK and client support the following networks:</p>
<ol>
<li><p>Base</p>
</li>
<li><p>Optimism</p>
</li>
<li><p>Polygon</p>
</li>
<li><p>BNB Chain</p>
</li>
<li><p>Arbitrum</p>
</li>
<li><p>Avalanche</p>
</li>
<li><p>Zora</p>
</li>
<li><p>Ethereum Mainnet (very expensive)</p>
</li>
<li><p>Ethereum Sepolia (Testnet)</p>
</li>
<li><p>Base Sepolia (Testnet)</p>
</li>
<li><p>Optimism Sepolia (Testnet)</p>
</li>
</ol>
<h3 id="heading-why-smart-wallet">Why Smart Wallet?</h3>
<ol>
<li><p><strong>Users can get free sponsored transactions</strong>: Use Paymaster to sponsor transactions and you could qualify for up to $15k in gas credits.</p>
</li>
<li><p><strong>Support Sub-Accounts:</strong> Let your app create and manage extra onchain accounts for users, all controlled by their main smart wallet — no more constant transaction pop-ups or signatures for every small action.</p>
</li>
<li><p><strong>Batch Operations:</strong> You can now perform multiple operations in a single transaction with the help of a smart wallet</p>
</li>
<li><p><strong>ERC-20 Paymaster</strong>: Let Users Pay Gas with Your App Token.<br /> Instead of forcing users to top up ETH just to use your app, <strong>ERC-20 paymasters</strong> let them pay gas fees using <em>your</em> app's native token (e.g., $VIBES, $AFRICOIN).</p>
</li>
</ol>
<h3 id="heading-adding-smart-wallet-to-an-existing-nextjs-project">Adding Smart Wallet To An Existing Next.js Project</h3>
<p>This guide would help you add smart wallet to an existing <a target="_blank" href="https://nextjs.org">Next.js</a> application using <a target="_blank" href="https://wagmi.sh">Wagmi</a>. Github Demo <a target="_blank" href="https://github.com/Base-West-Africa/Demo-examples/tree/main/smart-wallet-demo">Here</a></p>
<p><strong>Step 1: Install Dependencies</strong></p>
<p>First, navigate to your project directory and install the required dependencies</p>
<pre><code class="lang-plaintext">npm install @coinbase/wallet-sdk wagmi viem @tanstack/react-query
</code></pre>
<p><strong>Step 2: Create Wagmi Config</strong></p>
<p>Your project should have a <code>wagmi.ts</code> file, if it does not have one then you should proceed to create one in the root directory of your project.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { http, createConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;
<span class="hljs-keyword">import</span> { baseSepolia } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi/chains"</span>;
<span class="hljs-keyword">import</span> { coinbaseWallet } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi/connectors"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> cbWalletConnector = coinbaseWallet({
  appName: <span class="hljs-string">"Wagmi Smart Wallet"</span>,
  preference: <span class="hljs-string">"smartWalletOnly"</span>,
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = createConfig({
  chains: [baseSepolia],
  <span class="hljs-comment">// turn off injected provider discovery</span>
  multiInjectedProviderDiscovery: <span class="hljs-literal">false</span>,
  connectors: [cbWalletConnector],
  ssr: <span class="hljs-literal">true</span>,
  transports: {
    [baseSepolia.id]: http(),
  },
});

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">module</span> "wagmi" {
  <span class="hljs-keyword">interface</span> Register {
    config: <span class="hljs-keyword">typeof</span> config;
  }
}
</code></pre>
<p>We just had to modify the wagmi config to include the Smart Wallet connector <code>cbWalletConnector</code></p>
<p><strong>Step 3: Create Providers Component</strong></p>
<p>Create a file called <code>providers.tsx</code> in the <code>app/</code> directory:</p>
<pre><code class="lang-typescript"><span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { QueryClient, QueryClientProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</span>;
<span class="hljs-keyword">import</span> { useState, <span class="hljs-keyword">type</span> ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { WagmiProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;

<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/wagmi"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Providers</span>(<span class="hljs-params">props: { children: ReactNode }</span>) </span>{
  <span class="hljs-keyword">const</span> [queryClient] = useState(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> QueryClient());

  <span class="hljs-keyword">return</span> (
    &lt;WagmiProvider config={config}&gt;
      &lt;QueryClientProvider client={queryClient}&gt;
        {props.children}
      &lt;/QueryClientProvider&gt;
    &lt;/WagmiProvider&gt;
  );
}
</code></pre>
<p><strong>Step 4: Add Providers to the Root Layout</strong></p>
<p>Update the root layout file (app/layout.tsx):</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">"./globals.css"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { Providers } <span class="hljs-keyword">from</span> <span class="hljs-string">"./providers"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  title: <span class="hljs-string">"Smart Wallet App"</span>,
  description: <span class="hljs-string">"Smart Wallet Next.js integration"</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">props: { children: ReactNode }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html lang=<span class="hljs-string">"en"</span>&gt;
      &lt;body&gt;
        &lt;Providers&gt;{props.children}&lt;/Providers&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<p><strong>Step 5: Set Up Wallet Connection + SIWE (Sign-In With Ethereum)</strong></p>
<p>Now let’s create a component that handles:</p>
<ul>
<li><p>Connecting the Smart Wallet using Coinbase’s connector</p>
</li>
<li><p>Triggering <strong>Sign-In With Ethereum (SIWE)</strong> for authentication</p>
</li>
</ul>
<p>Create a file called <code>ConnectAndSIWE.tsx</code> in your <code>components/</code> directory and set up the logic to:</p>
<ul>
<li><p>Connect to the smart wallet</p>
</li>
<li><p>Prepare and sign the SIWE message</p>
</li>
<li><p>Verify the signature</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useCallback, useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Hex } <span class="hljs-keyword">from</span> <span class="hljs-string">"viem"</span>;
<span class="hljs-keyword">import</span> {
  useAccount,
  useConnect,
  usePublicClient,
  useSignMessage,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;
<span class="hljs-keyword">import</span> { SiweMessage } <span class="hljs-keyword">from</span> <span class="hljs-string">"siwe"</span>;
<span class="hljs-keyword">import</span> { cbWalletConnector } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/wagmi"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ConnectAndSIWE</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { connect } = useConnect({
    mutation: {
      onSuccess: <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> address = data.accounts[<span class="hljs-number">0</span>];
        <span class="hljs-keyword">const</span> chainId = data.chainId;
        <span class="hljs-keyword">const</span> m = <span class="hljs-keyword">new</span> SiweMessage({
          domain: <span class="hljs-built_in">document</span>.location.host,
          address,
          chainId,
          uri: <span class="hljs-built_in">document</span>.location.origin,
          version: <span class="hljs-string">"1"</span>,
          statement: <span class="hljs-string">"Smart Wallet SIWE Example"</span>,
          nonce: <span class="hljs-string">"12345678"</span>, <span class="hljs-comment">// Replace with a real nonce in production</span>
        });
        setMessage(m);
        signMessage({ message: m.prepareMessage() });
      },
    },
  });

  <span class="hljs-keyword">const</span> account = useAccount();
  <span class="hljs-keyword">const</span> client = usePublicClient();
  <span class="hljs-keyword">const</span> [signature, setSignature] = useState&lt;Hex | <span class="hljs-literal">undefined</span>&gt;();
  <span class="hljs-keyword">const</span> { signMessage } = useSignMessage({
    mutation: { onSuccess: <span class="hljs-function">(<span class="hljs-params">sig</span>) =&gt;</span> setSignature(sig) },
  });

  <span class="hljs-keyword">const</span> [message, setMessage] = useState&lt;SiweMessage | <span class="hljs-literal">undefined</span>&gt;();
  <span class="hljs-keyword">const</span> [valid, setValid] = useState&lt;<span class="hljs-built_in">boolean</span> | <span class="hljs-literal">undefined</span>&gt;();

  <span class="hljs-keyword">const</span> checkValid = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (!signature || !account.address || !client || !message) <span class="hljs-keyword">return</span>;
    <span class="hljs-keyword">const</span> v = <span class="hljs-keyword">await</span> client.verifyMessage({
      address: account.address,
      message: message.prepareMessage(),
      signature,
    });
    setValid(v);
  }, [signature, account.address, client, message]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    checkValid();
  }, [signature]);

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> connect({ connector: cbWalletConnector })}&gt;
        Connect + SIWE
      &lt;/button&gt;
      {valid !== <span class="hljs-literal">undefined</span> &amp;&amp; &lt;p&gt;Is valid: {valid.toString()}&lt;/p&gt;}
    &lt;/div&gt;
  );
}
</code></pre>
<p><strong>Step 6: Use the Component in a Page</strong></p>
<p>Add the component to <code>app/page.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ConnectAndSIWE } <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/ConnectAndSIWE'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;main&gt;
      &lt;h1&gt;Smart Wallet Integration&lt;/h1&gt;
      &lt;ConnectAndSIWE /&gt;
    &lt;/main&gt;
  )
}
</code></pre>
]]></content:encoded></item></channel></rss>