Web3 Modal and Virtual TestNets
Web3Modal SDK simplifies connecting Web3 dapps to wallets, offering a user-friendly interface for executing actions like signing transactions and interacting with smart contracts on the blockchain.
You can use a Virtual Testnet as a chain for UI development, testing, and dapp demo mode.
Create a Virtual TestNet
In Tenderly Dashboard, create a new Virtual TestNet:
- Select Mainnet as the base network
- Name it
Web3 Modal TestNet
- Choose a unique chain ID
73571
- Turn on the Public Explorer
- Copy the Testnet RPC
Create a Chain Config
Create a file src/tenderly.config.ts
and replace the following:
- Paste the chain ID to the
id
property - Change the name and currency
- Paste the Public RPC to
rpcUrls.default.http
- Paste the Block Explorer URL to
blockExplorers.default.url
import { defineChain } from 'viem'
export const vMainnet = defineChain({
id: 73571,
name: 'Virtual Ethereum Mainnet',
nativeCurrency: { name: 'vEther', symbol: 'vETH', decimals: 18 },
rpcUrls: {
default: { http: [process.env.TENDERLY_VIRTUAL_MAINNET_RPC!] }
},
blockExplorers: {
default: {
name: 'Tenderly Explorer',
url: 'https://dashboard.tenderly.co/explorer/vnet/47cdac98-cda3-431a-8fce-9f31037a3d0c'
}
},
contracts: {
ensRegistry: {
address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'
},
ensUniversalResolver: {
address: '0xE4Acdd618deED4e6d2f03b9bf62dc6118FC9A4da',
blockCreated: 16773775
},
multicall3: {
address: '0xca11bde05977b3631167028862be2a173976ca11',
blockCreated: 14353601
}
}
})
Create a Wagmi Config
Create a Wagmi config that will:
- include the
vMainnet
chain we defined in the previous step - Specify the Public RPC in
transport
undervMainnet.id
import { cookieStorage, createConfig, createStorage, http } from 'wagmi'
import { mainnet } from 'wagmi/chains'
import { vMainnet } from '@/tenderly.config'
import { injected } from '@wagmi/core'
// Get projectId at https://cloud.walletconnect.com
export const projectId = process.env.NEXT_PUBLIC_PROJECT_ID
if (!projectId) throw new Error('Project ID is not defined')
// Create wagmiConfig
export const config = createConfig({
chains: [mainnet, vMainnet],
connectors: [
injected()
],
ssr: true,
transports: {
[mainnet.id]: http('https://mainnet.gateway.tenderly.co/'),
[vMainnet.id]: http(process.env.TENDERLY_VIRTUAL_MAINNET_RPC!)
},
storage: createStorage({
storage: cookieStorage
}),
})
Create a Web3ModalProvider
Create a Web3ModalProvider
that will wrap your application.
To use the Virtual Testnet only while building UI, testing, and demoing the dapp, we added a NEXT_PUBLIC_TENDERLY_VNETS_ENABLED
environment variable.
The call to createWeb3Modal
uses vMainnet
as the default chain, when app runs with NEXT_PUBLIC_TENDERLY_VNETS_ENABLED
.
In this example, we used the w3m-button
web-component to trigger the Web3 Modal.
'use client'
import React, { ReactNode } from 'react'
import { wagmiConfig, projectId } from './wagmi.config'
import { createWeb3Modal } from '@web3modal/wagmi/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { State, WagmiProvider } from 'wagmi'
import { vMainnet } from '@/tenderly.config'
// Setup queryClient
const queryClient = new QueryClient()
if (!projectId) throw new Error('Project ID is not defined')
// Create modal
createWeb3Modal({
wagmiConfig: wagmiConfig,
projectId,
enableAnalytics: true, // Optional - defaults to your Cloud configuration
enableOnramp: true, // Optional - false as default
defaultChain: process.env.NEXT_PUBLIC_TENDERLY_VNETS_ENABLED === 'true' ? vMainnet : wagmiConfig.chains[0]
})
export default function Web3ModalProvider({ children, initialState }: {
children: ReactNode
initialState?: State
}) {
return (
<WagmiProvider config={wagmiConfig} initialState={initialState}>
<QueryClientProvider client={queryClient}>
<w3m-button />
{children}
</QueryClientProvider>
</WagmiProvider>
)
}
Use the Web3ModalProvider
Wrap your dapp body
(app/layout.tsx
) in a Web3ModalProvider
we created in the last step.
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
import Web3ModalProvider from '@/Web3ModalProvider';
const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) {
return (
<html lang="en">
<body className={inter.className}>
<Web3ModalProvider>
{children}
</Web3ModalProvider>
</body>
</html>
);
}
Run the dapp
## Get projectId at https://cloud.walletconnect.com
NEXT_PUBLIC_PROJECT_ID=???? \
NEXT_PUBLIC_TENDERLY_VNETS_ENABLED=true \
pnpm run dev
You should see