Web3Auth PnP Modal React Quick Start
This guide is designed to help you quickly integrate a basic instance of Web3Auth Plug and Play Modal in your React app.
If you face any problem anytime, you can always find help in the Web3Auth Community.
-
Clone the PnP Modal React Quick Start Application
- npm
- Yarn
- pnpm
npx degit Web3Auth/web3auth-pnp-examples/web-modal-sdk/quick-starts/react-modal-quick-start w3a-quick-start
yarn dlx degit Web3Auth/web3auth-pnp-examples/web-modal-sdk/quick-starts/react-modal-quick-start w3a-quick-start
pnpm dlx degit Web3Auth/web3auth-pnp-examples/web-modal-sdk/quick-starts/react-modal-quick-start w3a-quick-start
-
Install & Run
- npm
- Yarn
- pnpm
cd w3a-quick-start
npm install
npm run startcd w3a-quick-start
yarn install
yarn run startcd w3a-quick-start
pnpm install
pnpm run start
Install Web3Auth
Install the Web3Auth package in your project.
- npm
- Yarn
- pnpm
npm install --save @web3auth/modal @web3auth/base @web3auth/ethereum-provider
yarn add @web3auth/modal @web3auth/base @web3auth/ethereum-provider
pnpm add @web3auth/modal @web3auth/base @web3auth/ethereum-provider
Fixing Bundler Issues
While using Web3Auth in React, you may run into issues building. This issue occurs because some core
packages like eccrypto
have certain dependencies which are not present within the browser build
environment.
To solve this, please have a look at our troubleshooting pages:
Get your Client ID from the Web3Auth Dashboard
Visit the Web3Auth Dashboard and create a new project. Use the Client ID of the project to start your integration.
Go to the Developer DashboardPreparing Chain Config
Web3Auth is blockchain and library agnostic. This example is focused towards EVM Blockchains, however using methods, you can configure the app for your chain and library of choice.
While initializing Web3Auth, you will need to set up a basic chain config for the chain of your choice. A simple integration for some of the popular blockchains will look like this:
- EVM Chains
- Polygon
- Solana
- Any Other Blockchain
import { CHAIN_NAMESPACES } from "@web3auth/base";
const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth",
// Avoid using public rpcTarget in production.
// Use services like Infura, Quicknode etc
displayName: "Ethereum Mainnet",
blockExplorerUrl: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
logo: "https://cryptologos.cc/logos/ethereum-eth-logo.png",
};
import { CHAIN_NAMESPACES } from "@web3auth/base";
const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x89", // hex of 137, polygon mainnet
rpcTarget: "https://rpc.ankr.com/polygon",
// Avoid using public rpcTarget in production.
// Use services like Infura, Quicknode etc
displayName: "Polygon Mainnet",
blockExplorerUrl: "https://polygonscan.com",
ticker: "POL",
tickerName: "Polygon Ecosystem Token",
logo: "https://cryptologos.cc/logos/polygon-matic-logo.png",
};
import { SolanaPrivateKeyProvider } from "@web3auth/solana-provider";
import { AuthAdapter } from "@web3auth/auth-adapter";
import { CHAIN_NAMESPACES } from "@web3auth/base";
const chainConfig: {
chainNamespace: CHAIN_NAMESPACES.SOLANA;
chainId: "0x1"; // Please use 0x1 for Mainnet, 0x2 for Testnet, 0x3 for Devnet
rpcTarget: "https://rpc.ankr.com/solana";
displayName: "Solana Mainnet";
blockExplorerUrl: "https://explorer.solana.com";
ticker: "SOL";
tickerName: "Solana";
logo: "https://images.toruswallet.io/solana.svg";
};
const privateKeyProvider = new SolanaPrivateKeyProvider({
config: { chainConfig },
});
const authAdapter = new AuthAdapter({ privateKeyProvider: privateKeyProvider });
web3auth.configureAdapter(authAdapter);
import { CommonPrivateKeyProvider } from "@web3auth/base-provider";
import { AuthAdapter } from "@web3auth/auth-adapter";
import { CHAIN_NAMESPACES } from "@web3auth/base";
const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.OTHER,
chainId: "0x4e454152",
rpcTarget: "https://mainnet.aurora.dev",
// Avoid using public rpcTarget in production.
displayName: "Near",
blockExplorerUrl: "https://aurorascan.dev",
ticker: "NEAR",
tickerName: "NEAR",
};
const privateKeyProvider = new CommonPrivateKeyProvider({
config: { chainConfig },
});
const authAdapter = new AuthAdapter({ privateKeyProvider: privateKeyProvider });
web3auth.configureAdapter(authAdapter);
Initialize Web3Auth
Web3Auth needs to be initialized as soon as your app loads up to enable the user to log in. Preferably done within a constructor, initialization is the step where you can pass on all the configurations for Web3Auth you want.
For initializing Web3Auth PnP Modal SDK, you need to provide your Client ID, the Web3Auth Network of your project and the configuration of the chain you're looking to connect to.
Logging in your User
Use the connect
function in the Web3Auth Instance to display the modal. The modal will prompt the user to login with their wallet and handle the
authentication for you.
After a successful user login, the connect
function returns a provider that can be used to interact with the blockchain and sign transactions.
Get User Info
Once logged in, Web3Auth state exposes some information about your logged in user. This is fetched directly from the JWT token and Web3Auth doesn't store this info anywhere.
This information can help you identify your users and provide a more personalized experience.
Making Blockchain Calls
Web3Auth is chain agnostic. This means that you can use it with any blockchain with the provider exposed by Web3Auth. For EVM and Solana Blockchains Web3Auth exposes special providers for native integrations.
This example demonstrates the connection for an EVM Chain with Web3Auth. You can choose the library of your choice and configure it according the steps given in the respective RPC Files.
Have a look at our Connect Blockchain section of the documentation and choose your blockchain to get started.
Log the user out
Use the logout
function of the Web3Auth Instance to log the user out. This will also delete the session information from the local storage of the
browser.
- App.tsx
- vite.config.ts
- index.html
- package.json
- ethersRPC.ts
- viemRPC.ts
- web3RPC.ts
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable no-console */
import "./App.css";
import { CHAIN_NAMESPACES, IAdapter, IProvider, WEB3AUTH_NETWORK } from "@web3auth/base";
import { EthereumPrivateKeyProvider } from "@web3auth/ethereum-provider";
import { Web3Auth, Web3AuthOptions } from "@web3auth/modal";
import { getDefaultExternalAdapters } from "@web3auth/default-evm-adapter";
import { useEffect, useState } from "react";
import RPC from "./ethersRPC";
// import RPC from "./viemRPC";
// import RPC from "./web3RPC";
const clientId = "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ"; // get from https://dashboard.web3auth.io
const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0xaa36a7",
rpcTarget: "https://rpc.ankr.com/eth_sepolia",
// Avoid using public rpcTarget in production.
// Use services like Infura, Quicknode etc
displayName: "Ethereum Sepolia Testnet",
blockExplorerUrl: "https://sepolia.etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
logo: "https://cryptologos.cc/logos/ethereum-eth-logo.png",
};
const privateKeyProvider = new EthereumPrivateKeyProvider({
config: { chainConfig },
});
const web3AuthOptions: Web3AuthOptions = {
clientId,
web3AuthNetwork: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
privateKeyProvider,
}
const web3auth = new Web3Auth(web3AuthOptions);
const adapters = await getDefaultExternalAdapters({ options: web3AuthOptions });
adapters.forEach((adapter: IAdapter<unknown>) => {
web3auth.configureAdapter(adapter);
});
function App() {
const [provider, setProvider] = useState<IProvider | null>(null);
const [loggedIn, setLoggedIn] = useState(false);
useEffect(() => {
const init = async () => {
try {
await web3auth.initModal();
setProvider(web3auth.provider);
if (web3auth.connected) {
setLoggedIn(true);
}
} catch (error) {
console.error(error);
}
};
init();
}, []);
const login = async () => {
const web3authProvider = await web3auth.connect();
setProvider(web3authProvider);
if (web3auth.connected) {
setLoggedIn(true);
}
};
const getUserInfo = async () => {
const user = await web3auth.getUserInfo();
uiConsole(user);
};
const logout = async () => {
await web3auth.logout();
setProvider(null);
setLoggedIn(false);
uiConsole("logged out");
};
// Check the RPC file for the implementation
const getAccounts = async () => {
if (!provider) {
uiConsole("provider not initialized yet");
return;
}
const address = await RPC.getAccounts(provider);
uiConsole(address);
};
const getBalance = async () => {
if (!provider) {
uiConsole("provider not initialized yet");
return;
}
const balance = await RPC.getBalance(provider);
uiConsole(balance);
};
const signMessage = async () => {
if (!provider) {
uiConsole("provider not initialized yet");
return;
}
const signedMessage = await RPC.signMessage(provider);
uiConsole(signedMessage);
};
const sendTransaction = async () => {
if (!provider) {
uiConsole("provider not initialized yet");
return;
}
uiConsole("Sending Transaction...");
const transactionReceipt = await RPC.sendTransaction(provider);
uiConsole(transactionReceipt);
};
function uiConsole(...args: any[]): void {
const el = document.querySelector("#console>p");
if (el) {
el.innerHTML = JSON.stringify(args || {}, null, 2);
console.log(...args);
}
}
const loggedInView = (
<>
<div className="flex-container">
<div>
<button onClick={getUserInfo} className="card">
Get User Info
</button>
</div>
<div>
<button onClick={getAccounts} className="card">
Get Accounts
</button>
</div>
<div>
<button onClick={getBalance} className="card">
Get Balance
</button>
</div>
<div>
<button onClick={signMessage} className="card">
Sign Message
</button>
</div>
<div>
<button onClick={sendTransaction} className="card">
Send Transaction
</button>
</div>
<div>
<button onClick={logout} className="card">
Log Out
</button>
</div>
</div>
</>
);
const unloggedInView = (
<button onClick={login} className="card">
Login
</button>
);
return (
<div className="container">
<h1 className="title">
<a target="_blank" href="https://web3auth.io/docs/sdk/pnp/web/modal" rel="noreferrer">
Web3Auth{" "}
</a>
& React Quick Start
</h1>
<div className="grid">{loggedIn ? loggedInView : unloggedInView}</div>
<div id="console" style={{ whiteSpace: "pre-line" }}>
<p style={{ whiteSpace: "pre-line" }}></p>
</div>
<footer className="footer">
<a
href="https://github.com/Web3Auth/web3auth-pnp-examples/tree/main/web-modal-sdk/quick-starts/react-vite-modal-quick-start"
target="_blank"
rel="noopener noreferrer"
>
Source code
</a>
<a href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FWeb3Auth%2Fweb3auth-pnp-examples%2Ftree%2Fmain%2Fweb-modal-sdk%2Fquick-starts%2Freact-vite-evm-modal-quick-start&project-name=w3a-react-vite-no-modal&repository-name=w3a-react-vite-no-modal">
<img src="https://vercel.com/button" alt="Deploy with Vercel" />
</a>
</footer>
</div>
);
}
export default App;