Integrate Embedded Wallets with the Zircuit Blockchain in JavaScript
Chain Details for Zircuit
- Mainnet
- Testnet
- Chain ID: 0xBF04 (hex of 48900)
- Public RPC URL: https://zircuit1-mainnet.p2pify.com/ (Avoid using public rpcTarget in production)
- Display Name: Zircuit Mainnet
- Block Explorer Link: https://explorer.zircuit.com
- Ticker: ETH
- Ticker Name: ETH
- Chain ID: 0xBF03 (hex of 48899)
- Public RPC URL: https://zircuit1.p2pify.com/ (Avoid using public rpcTarget in production)
- Display Name: Zircuit Testnet
- Block Explorer Link: https://explorer.testnet.zircuit.com
- Ticker: ETH
- Ticker Name: ETH
React Wagmi Integration
You need to install the wagmi and @tanstack/react-query packages and use the Web3Auth
implementation of WagmiProvider for configuration.
The Web3Auth implementation of WagmiProvider is a custom implementation that is used to integrate
with the Web3Auth Modal SDK. It is a wrapper around the WagmiProvider that makes it compatible.
With this implementation, you can use the Wagmi hooks, however no external connectors are supported. Web3Auth provides a whole suite of connectors which you can use directly for a better experience with external wallets.
- npm
- Yarn
- pnpm
- Bun
npm install wagmi @tanstack/react-query
yarn add wagmi @tanstack/react-query
pnpm add wagmi @tanstack/react-query
bun add wagmi @tanstack/react-query
import "./index.css";
import ReactDOM from "react-dom/client";
import { Web3AuthProvider } from "@web3auth/modal/react";
import web3AuthContextConfig from "./web3authContext";
import { WagmiProvider } from "@web3auth/modal/react/wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import App from "./App";
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<Web3AuthProvider config={web3AuthContextConfig}>
<QueryClientProvider client={queryClient}>
<WagmiProvider>
<App />
</WagmiProvider>
</QueryClientProvider>
</Web3AuthProvider>,
);
Wagmi provides a comprehensive set of React hooks for Ethereum and EVM-compatible chains. Web3Auth
integrates seamlessly with Wagmi, so you can use hooks like useAccount, useBalance,
useSendTransaction, and more, out of the box.
Below are some examples of using Wagmi hooks in your dApp after Web3Auth and Wagmi are set up. You can note these functions work directly with Wagmi. Once you have set up Wagmi with Web3Auth, you can use any Wagmi hook as you would in a standard Wagmi application.
Get Account Balance
import { useAccount, useBalance } from "wagmi";
import { formatUnits } from "viem";
export function Balance() {
const { address } = useAccount();
const { data, isLoading, error } = useBalance({ address });
return (
<div>
<h2>Balance</h2>
<div>
{data?.value !== undefined && `${formatUnits(data.value, data.decimals)} ${data.symbol}`}{" "}
{isLoading && "Loading..."} {error && "Error: " + error.message}
</div>
</div>
);
}
Send Transaction
import { FormEvent } from "react";
import { useWaitForTransactionReceipt, useSendTransaction, BaseError } from "wagmi";
import { Hex, parseEther } from "viem";
export function SendTransaction() {
const { data: hash, error, isPending, sendTransaction } = useSendTransaction();
async function submit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
const to = formData.get("address") as Hex;
const value = formData.get("value") as string;
sendTransaction({ to, value: parseEther(value) });
}
const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({
hash,
});
return (
<div>
<h2>Send Transaction</h2>
<form onSubmit={submit}>
<input name="address" placeholder="Address" required />
<input name="value" placeholder="Amount (ETH)" type="number" step="0.000000001" required />
<button disabled={isPending} type="submit">
{isPending ? "Confirming..." : "Send"}
</button>
</form>
{hash && <div>Transaction Hash: {hash}</div>}
{isConfirming && "Waiting for confirmation..."}
{isConfirmed && "Transaction confirmed."}
{error && <div>Error: {(error as BaseError).shortMessage || error.message}</div>}
</div>
);
}
Switch Chain
import { useChainId, useSwitchChain } from "wagmi";
export function SwitchChain() {
const chainId = useChainId();
const { chains, switchChain, error } = useSwitchChain();
return (
<div>
<h2>Switch Chain</h2>
<h3>Connected to {chainId}</h3>
{chains.map((chain) => (
<button
disabled={chainId === chain.id}
key={chain.id}
onClick={() => switchChain({ chainId: chain.id })}
type="button"
className="card"
>
{chain.name}
</button>
))}
{error?.message}
</div>
);
}
Vue Wagmi Integration
You need to install the wagmi & @tanstack/vue-query packages and use the Web3Auth
implementation of WagmiProvider for configuration.
The Web3Auth implementation of WagmiProvider is a custom implementation that is used to integrate
with the Web3Auth Modal SDK. It is a wrapper around the WagmiProvider that makes it compatible.
With this implementation, you can use the Wagmi composables, however no external connectors are supported. Web3Auth provides a whole suite of connectors which you can use directly for a better experience with external wallets.
npm install wagmi @tanstack/vue-query
Update your main.ts to use the Vue Query plugin only if you are using Wagmi:
import { VueQueryPlugin } from "@tanstack/vue-query";
import { createApp } from "vue";
import App from "./App.vue";
import "./style.css";
createApp(App).use(VueQueryPlugin).mount("#app");
Then, in your App.vue, wrap your app with both providers:
<script setup lang="ts">
import Home from "./Home.vue";
import { Web3AuthProvider } from "@web3auth/modal/vue";
import { WagmiProvider } from "@web3auth/modal/vue/wagmi";
import web3AuthContextConfig from "./web3authContext";
</script>
<template>
<div class="min-h-screen flex flex-col">
<Web3AuthProvider :config="web3AuthContextConfig">
<WagmiProvider>
<Home />
</WagmiProvider>
</Web3AuthProvider>
</div>
</template>
Wagmi provides a comprehensive set of composables for Ethereum and EVM-compatible chains in Vue.
Web3Auth integrates seamlessly with Wagmi, so you can use composables like useAccount,
useBalance, useSendTransaction, and more, out of the box.
Below are some examples of using Wagmi composables in your dApp after Web3Auth and Wagmi are set up. You can note these functions work directly with Wagmi. Once you have set up Wagmi with Web3Auth, you can use any Wagmi composable as you would in a standard Wagmi application.
Get Account Balance
<script setup lang="ts">
import { useAccount, useBalance } from "wagmi";
import { formatUnits } from "viem";
import { computed } from "vue";
const { address } = useAccount();
const { data, isLoading, error } = useBalance(computed(() => ({ address: address.value })));
</script>
<template>
<div>
<h2>Balance</h2>
<div>
<span v-if="data && data.value !== undefined">
{{ formatUnits(data.value, data.decimals) }} {{ data.symbol }}
</span>
<span v-if="isLoading">Loading...</span>
<span v-if="error">Error: {{ error.message }}</span>
</div>
</div>
</template>
Send Transaction
<script setup lang="ts">
import { ref } from "vue";
import { useSendTransaction, useWaitForTransactionReceipt } from "wagmi";
import { parseEther } from "viem";
const address = ref("");
const value = ref("");
const { data: hash, error, isPending, sendTransaction } = useSendTransaction();
function submit() {
sendTransaction({
to: address.value,
value: parseEther(value.value),
});
}
const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({
hash,
});
</script>
<template>
<div>
<h2>Send Transaction</h2>
<form @submit.prevent="submit">
<input v-model="address.value" name="address" placeholder="Address" required />
<input
v-model="value.value"
name="value"
placeholder="Amount (ETH)"
type="number"
step="0.000000001"
required
/>
<button :disabled="isPending" type="submit">
{{ isPending ? "Confirming..." : "Send" }}
</button>
</form>
<div v-if="hash">Transaction Hash: {{ hash }}</div>
<div v-if="isConfirming">Waiting for confirmation...</div>
<div v-if="isConfirmed">Transaction confirmed.</div>
<div v-if="error">Error: {{ error.shortMessage || error.message }}</div>
</div>
</template>
Switch Chain
<script setup lang="ts">
import { useChainId, useSwitchChain } from "wagmi";
const chainId = useChainId();
const { chains, switchChain, error } = useSwitchChain();
</script>
<template>
<div>
<h2>Switch Chain</h2>
<h3>Connected to {{ chainId }}</h3>
<div>
<button
v-for="chain in chains"
:key="chain.id"
:disabled="chainId === chain.id"
@click="switchChain({ chainId: chain.id })"
type="button"
class="card"
>
{{ chain.name }}
</button>
</div>
<div v-if="error">{{ error.message }}</div>
</div>
</template>
For VanillaJS, Angular and other frameworks
Installation
To interact with the blockchain, you can use either the viem or
ethers.js library with Web3Auth.
- viem
- ethers.js
- npm
- Yarn
- pnpm
- Bun
npm install --save viem
yarn add viem
pnpm add viem
bun add viem
- npm
- Yarn
- pnpm
- Bun
npm install --save ethers
yarn add ethers
pnpm add ethers
bun add ethers
Initializing Provider
Using eip155 as chainNamespace while initializing web3auth will provide an
EIP1193 compatible provider as web3auth.provider
after successful authentication.
Initializing and instantiating the Web3Auth SDK
import { Web3Auth, WEB3AUTH_NETWORK } from "@web3auth/modal";
const web3AuthOptions: Web3AuthOptions = {
clientId,
web3AuthNetwork: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
};
Getting the Web3Auth provider
After initializing Web3Auth, the next step is to initialize the provider and use it for your operations.
// Initialize for PnP Web SDK
await web3auth.init();
// Trigger the login
await web3auth.connect();
// await web3auth.connectTo(); // For custom flow
// Get the provider
const provider = web3auth.provider;
// Continue using the `provider`
Get Account and Balance
- viem
- ethers.js
/*
Use code from the above Initializing Provider here
*/
// provider is const provider = new ethers.providers.Web3Provider(web3Auth.provider); from above.
// For ethers v5
// const signer = ethersProvider.getSigner();
const signer = await ethersProvider.getSigner();
// Get user's Ethereum public address
const address = signer.getAddress();
// Get user's balance in ether
// For ethers v5
// const balance = ethers.utils.formatEther(
// await ethersProvider.getBalance(address) // Balance is in wei
// );
const balance = ethers.utils.formatEther(
await provider.getBalance(address), // Balance is in wei
);
const publicClient = createPublicClient({
chain: mainnet, // for mainnet
transport: custom(this.provider),
});
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(this.provider),
});
// Get user's Ethereum public address
const address = await walletClient.getAddresses();
// Get user's balance in ether
const balance = await publicClient.getBalance({ address: address[0] });
Send Transaction
- viem
- ethers.js
/*
Use code from the above Initializing Provider here
*/
// provider is const provider = new ethers.providers.Web3Provider(web3Auth.provider); from above.
const signer = await provider.getSigner();
const destination = "0x7aFac68875d2841dc16F1730Fba43974060b907A";
const amount = ethers.parseEther("1.0"); // Convert 1 ether to wei
// Submit transaction to the blockchain
const tx = await signer.sendTransaction({
to: destination,
value: amount,
});
// Wait for the transaction to be mined
const receipt = await tx.wait();
/*
Use code from the above Initializing Provider here
*/
const publicClient = createPublicClient({
chain: mainnet, // for mainnet
transport: custom(this.provider),
});
const walletClient = createWalletClient({
chain: mainnet, // for mainnet
transport: custom(this.provider),
});
// data for the transaction
const destination = "<ADDRESS>";
const amount = parseEther("0.0001");
const address = await this.getAccounts();
const address = await walletClient.getAddresses();
// Submit transaction to the blockchain
const hash = await walletClient.sendTransaction({
account: address[0],
to: destination,
value: amount,
});
const receipt = await publicClient.waitForTransactionReceipt({ hash });
Send Transaction
- viem
- ethers.js
/*
Use code from the above Initializing Provider here
*/
// provider is const provider = new ethers.providers.Web3Provider(web3Auth.provider); from above.
const signer = await provider.getSigner();
const destination = "0x7aFac68875d2841dc16F1730Fba43974060b907A";
const amount = ethers.parseEther("1.0"); // Convert 1 ether to wei
// Submit transaction to the blockchain
const tx = await signer.sendTransaction({
to: destination,
value: amount,
});
// Wait for the transaction to be mined
const receipt = await tx.wait();
/*
Use code from the above Initializing Provider here
*/
const publicClient = createPublicClient({
chain: mainnet, // for mainnet
transport: custom(this.provider),
});
const walletClient = createWalletClient({
chain: mainnet, // for mainnet
transport: custom(this.provider),
});
// data for the transaction
const destination = "<ADDRESS>";
const amount = parseEther("0.0001");
const address = await this.getAccounts();
const address = await walletClient.getAddresses();
// Submit transaction to the blockchain
const hash = await walletClient.sendTransaction({
account: address[0],
to: destination,
value: amount,
});
const receipt = await publicClient.waitForTransactionReceipt({ hash });
Sign Message
Personal Sign
- viem
- ethers.js
/*
Use code from the above Initializing Provider here
*/
const provider = new ethers.providers.Web3Provider(web3Auth.provider);
const signer = await provider.getSigner();
const originalMessage = "YOUR_MESSAGE";
const signedMessage = await signer.signMessage(originalMessage);
/*
Use code from the above Initializing Provider here
*/
const publicClient = createPublicClient({
chain: mainnet, // for mainnet
transport: custom(this.provider),
});
const walletClient = createWalletClient({
chain: mainnet, // for mainnet
transport: custom(this.provider),
});
// data for signing
const address = await walletClient.getAddresses();
const originalMessage = "YOUR_MESSAGE";
// Sign the message
const hash = await walletClient.signMessage({
account: address[0],
message: originalMessage,
});