Create a React dapp with the SDK and Wagmi
This tutorial walks you through creating and integrating a simple React dapp with MetaMask SDK. You'll configure the SDK using Wagmi, a popular third-party library.
Wagmi offers React hooks that simplify wallet connections, transactions, and network interactions for Ethereum developers. With the integrated MetaMask SDK, the setup is streamlined, eliminating extra dependencies. The Metamask SDK connector in Wagmi allows developers to quickly build dapps that connect to MetaMask in React with minimal friction.
Scaffolding tools
You can use Create Wagmi or the Consensys Create Web3 CLI to scaffold out a basic ViteJS with React application, both of which will ensure that Viem and Wagmi are adequately configured. This tutorial uses Create Wagmi.
The Consensys Create Web3 CLI might be useful for future web3 development, as it not only generates a nearly identical front-end as Create Wagmi, but it also creates a monorepo (single repository containing both a blockchain and a React web client) with MetaMask SDK already wired up with a custom connect button.
Prerequisites
- Node.js version 20+
- npm version 9+
- A text editor (for example, VS Code)
- The MetaMask extension or MetaMask Flask installed
- Basic knowledge of React
Steps
1. Set up the project
- pnpm
- npm
pnpm create wagmi --template vite-react
npm create wagmi@latest --template vite-react
This command prompts you for a project name.
For example, use mmsdk-wagmi-tutorial
.
Once the CLI is complete, change directories into that project and install the node module dependencies:
- pnpm
- npm
cd mmsdk-wagmi-tutorial && pnpm install
cd mmsdk-wagmi-tutorial && npm install
Launch the development server:
npm run dev
This displays a localhost URL in your terminal for easy access to launch in your browser:
> mmsdk-wagmi--create-wagmi--vite-react@0.0.0 dev
> vite
VITE v5.4.9 ready in 1066 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
1.1. Review the Viem, Wagmi, and MetaMask SDK configuration
In src/main.tsx
, you can find the following WagmiProvider
which takes a config
and QueryClientProvider
.
QueryClientProvider
comes from the @tanstack/react-query
package, and wraps the application to
manage server-side data fetching, caching, and synchronization.
It helps you handle asynchronous data by providing a consistent way to fetch, cache, and update your
data across the app.
For web3 developers, this means your dapp can smoothly manage blockchain data or API calls without
needing to write custom state management logic.
import { Buffer } from "buffer"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import React from "react"
import ReactDOM from "react-dom/client"
import { WagmiProvider } from "wagmi"
import App from "./App.tsx"
import { config } from "./wagmi.ts"
import "./index.css"
globalThis.Buffer = Buffer
const queryClient = new QueryClient()
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>,
)
You get WagmiProvider
configuration from the following import statement:
import { config } from "./wagmi.ts"
And wagmi.ts
looks like the following:
import { http, createConfig } from "wagmi"
import { mainnet, sepolia } from "wagmi/chains"
import { coinbaseWallet, injected, walletConnect } from "wagmi/connectors"
export const config = createConfig({
chains: [mainnet, sepolia],
connectors: [
injected(),
coinbaseWallet(),
walletConnect({ projectId: import.meta.env.VITE_WC_PROJECT_ID }),
],
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
},
})
declare module "wagmi" {
interface Register {
config: typeof config
}
}
Wagmi's default uses mainnet
and sepolia
, which are defined in the chains
array.
Out of the box, they have also set up the injected
wallet provider, coinbaseWallet
, and walletConnect
.
You'll replace these with the MetaMask connector for the purpose of this tutorial and testing MetaMask SDK.
2. Update the Wagmi configuration
Modify this configuration to target the Linea testnet and use the Metamask connector, which is Wagmi's built-in support for MetaMask SDK:
import { http, createConfig } from "wagmi";
import { lineaSepolia } from "wagmi/chains";
import { metaMask } from "wagmi/connectors";
export const config = createConfig({
multiInjectedProviderDiscovery: false,
chains: [lineaSepolia],
connectors: [
metaMask({
dappMetadata: {
name: "MetaMask SDK + Wagmi Tutorial",
url: "https://wagmi.io",
iconUrl: "https://wagmi.io/favicon.ico",
},
}),
],
transports: {
[lineaSepolia.id]: http(
`https://linea-sepolia.infura.io/v3/<YOUR-API-KEY>`
),
},
});
This configures Wagmi with the following options:
multiInjectedProviderDiscovery
disables automatic discovery of multiple injected wallets, streamlining the wallet selection process.chains
specifies that the dapp will connect to the Linea Sepolia network.connectors
uses MetaMask as the primary wallet, and includes some dapp metadata (name, URL, and icon) for a branded user experience.transports
configures HTTP transport to connect to the Linea Sepolia network using an Infura API key for reliable access to blockchain data. Create an API key if you don't already have one.
This setup simplifies wallet integration and provides a smooth user experience while working with Linea Sepolia.
3. Connect to MetaMask extension or Mobile
At this point, your dapp displays, and you can connect to and disconnect from MetaMask. Your connection experience will be similar to that of using the injected provider, as most web3 users are experienced with.
By default, MetaMask SDK automatically connects to the MetaMask browser extension if it exists.
It does not show a QR code for linking to Metamask Mobile unless the MetaMask browser extension is
disabled or does not exist.
You can change this behavior by setting
extensionOnly
to false
.
To test connecting to MetaMask Mobile, disconnect from the MetaMask browser extension and disable MetaMask in your browser. Refresh your browser to simulate a new session. Now, when you select Connect Wallet, you'll see the QR code that you can use to connect to MetaMask Mobile.
3. Configure the SDK
You can configure any MetaMask JavaScript SDK options within the Wagmi configuration.
In wagmi.ts
, create a variable named metaMaskSDKOptions
:
const metaMaskSDKOptions = {
infuraAPIKey: "<YOUR-API-KEY>",
};
You can use the infuraAPIKey
option to
make direct, read-only JSON-RPC requests.
Pass metaMaskSDKOptions
into the metaMask()
function in connectors
and spread its values using
the ...
operator:
connectors: [
metaMask({
dappMetadata: {
name: "MetaMask SDK + Wagmi Tutorial",
url: "https://wagmi.io",
iconUrl: "https://wagmi.io/favicon.ico",
},
...metaMaskSDKOptions,
}),
],
4. Use additional SDK options
You can configure any number of SDK options in the
metaMaskSDKOptions
object to customize the behavior of the SDK.
In this section, you'll plug in options one by one to see how it affects the SDK.
Immediately check if MetaMask is installed
Use checkInstallationImmediately
to
enable or disable immediately checking if MetaMask is installed in the user's browser.
The default value is false
.
Set this to true
:
const metaMaskSDKOptions = {
checkInstallationImmediately: true,
};
Disable the MetaMask extension and re-load your dapp. When this option is enabled, the SDK immediately checks and notifies the user with a modal that they can either install the MetaMask extension or connect to MetaMask Mobile using a QR code.
Check if MetaMask is installed before RPC requests
Use checkInstallationOnAllCalls
to
enable or disable checking if MetaMask is installed before each JSON-RPC request.
The default value is false
.
Set this to true
:
const metaMaskSDKOptions = {
checkInstallationOnAllCalls: true
};
Disable the MetaMask extension and re-load your dapp.
Make a read-only RPC request without the InfuraAPIKey
.
You'll see a similar modal as in the previous test, but it will notify the user upon making the RPC request.
Send anonymous analytics to MetaMask
Use enableDebug
to enable or disable sending
anonymous analytics to MetaMask to help improve the SDK.
The default value is true
.
const metaMaskSDKOptions = {
enableDebug: true
};
This setting does not transmit any sensitive data. It only sends information that allows MetaMask to analyze and improve the behavior and core functionality of the SDK.
Map RPC URLs for read-only requests
Use readonlyRPCMap
to map RPC URLS for
read-only RPC requests.
You can use this option in conjunction with infuraAPIKey
and defaultReadOnlyChainId
.
For example, you want to make read-only requests to Mainnet (chain ID 0x1
) using the Infura API,
and read-only requests to the local testnet (chain ID 0x539
) use a custom node.
infuraAPIKey
provides access to various networks supported by Infura.
readonlyRPCMap
allows access to custom nodes and overrides Infura networks in case of a conflict.
You can use both the Infura API and custom nodes to make read-only requests by specifying both options:
const metaMaskSDKOptions = {
infuraAPIKey: "<YOUR-API-KEY>",
readonlyRPCMap: {
"0x539": "http://localhost:8545",
}
};
Conclusion
This tutorial walked you through generating a dapp using Create Wagmi, and configuring MetaMask SDK. You explored how the SDK works within a React application with Viem and Wagmi, how it behaves out of the box, and how to use a few key options to customize its behavior.