This package provides an embedded wallet connector for Wagmi, which is a commonly used React Hooks library for Ethereum.
Developers who use Wagmi in their application should be able to use the provided createCDPEmbeddedWalletConnector out of the box to integrate CDP embedded wallets into their existing environment.
This guide will help you get started with @coinbase/cdp-wagmi
. You'll learn how to install the package, set up the provider, and render your first component.
First, add the package to your project using your preferred package manager.
# With pnpm
pnpm add @coinbase/cdp-wagmi @coinbase/cdp-core @tanstack/react-query viem wagmi
# With yarn
yarn add @coinbase/cdp-wagmi @coinbase/cdp-core @tanstack/react-query viem wagmi
# With npm
npm install @coinbase/cdp-wagmi @coinbase/cdp-core @tanstack/react-query viem wagmi
http://localhost:3000
Next, you must configure your WagmiProvider with the CDPEmbeddedWalletConnector
.
CDPEmbeddedWalletConnector
provides the necessary context Wagmi to work correctly with
the CDP Frontend SDK. The providerConfig
must be provided and is responsible for
configuring the EIP-1193 provider's transports which are used to broadcast non-Base
transactions.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { App } from './App'; // Your main App component
import { Config }from '@coinbase/cdp-core';
import { createCDPEmbeddedWalletConector } from '@coinbase/cdp-wagmi';
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { http }from "viem";
import { baseSepolia, base } from 'viem/chains';
import { WagmiProvider, createConfig, http } from 'wagmi';
// Your CDP config
const cdpConfig: Config = {
projectId: "your-project-id", // Copy your Project ID here.
}
const connector = createCDPEmbeddedWalletConnector({
cdpConfig: cdpConfig,
providerConfig:{
chains: [base, baseSepolia],
transports: {
[base.id]: http(),
[baseSepolia.id]: http()
}
}
});
const wagmiConfig = createConfig({
connectors: [connector],
chains: [base, baseSepolia],
transports: {
[base.id]: http(),
[baseSepolia.id]: http(),
},
});
const queryClient = new QueryClient(); // For use with react-query
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<WagmiProvider config={wagmiConfig} >
<QueryClientProvider client={ queryClient }>
<App />
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>,
);
In order to connect the CDP Embedded Wallet, the end application user must first go through the 2 step sign in flow. As a result, the consumer has 3 options:
signInWithEmail
+ verifyEmailOTP
useSignInWithEmail
+ useVerifyEmailOTP
<SignIn />
componentAfter using any of these methods, the CDP embedded wallet's connector should automatically connect.
Now, your application should be able to successfully call Wagmi hooks. For example:
import { useState } from "react";
import { parseEther } from "viem";
import { useAccount, useSendTransaction, useWaitForTransactionReceipt } from "wagmi";
/**
* The burn address (0x0000000000000000000000000000000000000000)
*/
const BURN_ADDRESS = "0x0000000000000000000000000000000000000000" as const;
/**
* The amount to send in ETH (0.00001 ETH)
*/
const AMOUNT_TO_SEND = "0.00001";
/**
* A component that demonstrates wagmi's useSendTransaction hook
* by sending 0.00001 ETH to the burn address.
*
* @returns A component that allows the user to send a transaction using wagmi.
*/
export default function WagmiTransaction() {
const { address } = useAccount();
const [isLoading, setIsLoading] = useState(false);
const { data: hash, sendTransaction, isPending, error } = useSendTransaction();
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
hash,
});
const handleSendTransaction = async () => {
if (!address) return;
setIsLoading(true);
try {
sendTransaction({
to: BURN_ADDRESS,
value: parseEther(AMOUNT_TO_SEND),
});
} catch (error) {
console.error("Failed to send transaction:", error);
} finally {
setIsLoading(false);
}
};
const handleReset = () => {
// Reset by refreshing the page or clearing state
window.location.reload();
};
return (
<div>
<div>
<p>
⚠️ Warning: This will send {AMOUNT_TO_SEND} ETH to the burn address (0x0000...0000).
This transaction cannot be reversed and the ETH will be permanently lost.
</p>
</div>
<div>
<div>
<div>Amount: {AMOUNT_TO_SEND} ETH</div>
<div>To (Burn Address): {BURN_ADDRESS.slice(0, 6)}...{BURN_ADDRESS.slice(-4)}</div>
<div>From: {address?.slice(0, 6)}...{address?.slice(-4)}</div>
</div>
</div>
{error && (
<div>
<strong>Error:</strong> {error.message}
</div>
)}
{!hash && !isPending && !isLoading && (
<button disabled={!address} onClick={handleSendTransaction}>
Send {AMOUNT_TO_SEND} ETH to Burn Address
</button>
)}
{(isPending || isConfirming) && (
<div>
<div>Sending transaction...</div>
{hash && (
<div>
Hash: {hash.slice(0, 10)}...{hash.slice(-8)}
</div>
)}
</div>
)}
{isSuccess && hash && (
<div>
<div>
<div>✅</div>
</div>
<div>
<div>Transaction Confirmed!</div>
<div>Your transaction has been successfully sent to the burn address</div>
</div>
<div>
<div>Amount: {AMOUNT_TO_SEND} ETH</div>
<div>To: {BURN_ADDRESS.slice(0, 6)}...{BURN_ADDRESS.slice(-4)}</div>
<div>
Block Explorer:{" "}
<a
href={`https://sepolia.basescan.org/tx/${hash}`}
target="_blank"
rel="noopener noreferrer"
>
{hash.slice(0, 10)}...{hash.slice(-8)}
</a>
</div>
</div>
<button onClick={handleReset}>
Send Another Transaction →
</button>
</div>
)}
</div>
);
}