diff --git a/code/wagmi/.gitignore b/code/wagmi/.gitignore
new file mode 100644
index 00000000..d32cc78b
--- /dev/null
+++ b/code/wagmi/.gitignore
@@ -0,0 +1,40 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# env files (can opt-in for committing if needed)
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/code/wagmi/bun.lockb b/code/wagmi/bun.lockb
new file mode 100755
index 00000000..ffc50515
Binary files /dev/null and b/code/wagmi/bun.lockb differ
diff --git a/code/wagmi/next.config.ts b/code/wagmi/next.config.ts
new file mode 100644
index 00000000..0748d34f
--- /dev/null
+++ b/code/wagmi/next.config.ts
@@ -0,0 +1,8 @@
+import type { NextConfig } from 'next';
+
+const nextConfig: NextConfig = {
+ /* config options here */
+ reactStrictMode: true,
+};
+
+export default nextConfig;
diff --git a/code/wagmi/package.json b/code/wagmi/package.json
new file mode 100644
index 00000000..072c91b3
--- /dev/null
+++ b/code/wagmi/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "wagmi",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "@tanstack/react-query": "^5.60.4",
+ "@wagmi/connectors": "^5.3.10",
+ "@wagmi/core": "^2.14.6",
+ "next": "15.0.3",
+ "react": "19.0.0-rc-66855b96-20241106",
+ "react-dom": "19.0.0-rc-66855b96-20241106",
+ "viem": "^2.21.45",
+ "wagmi": "^2.12.32"
+ },
+ "devDependencies": {
+ "@types/node": "^20",
+ "@types/react": "^18",
+ "@types/react-dom": "^18",
+ "typescript": "^5"
+ }
+}
diff --git a/code/wagmi/public/favicon.ico b/code/wagmi/public/favicon.ico
new file mode 100644
index 00000000..718d6fea
Binary files /dev/null and b/code/wagmi/public/favicon.ico differ
diff --git a/code/wagmi/src/components/Account.tsx b/code/wagmi/src/components/Account.tsx
new file mode 100644
index 00000000..9d92f643
--- /dev/null
+++ b/code/wagmi/src/components/Account.tsx
@@ -0,0 +1,7 @@
+import { useAccount } from 'wagmi';
+
+export function Account() {
+ const { address } = useAccount();
+
+ return
{address}
;
+}
diff --git a/code/wagmi/src/components/AccountTS.tsx b/code/wagmi/src/components/AccountTS.tsx
new file mode 100644
index 00000000..f6a82484
--- /dev/null
+++ b/code/wagmi/src/components/AccountTS.tsx
@@ -0,0 +1,7 @@
+import { fetchAccount } from '@/utils/account';
+
+export function AccountTS() {
+ const address = fetchAccount();
+
+ return {address}
;
+}
diff --git a/code/wagmi/src/components/Balance.tsx b/code/wagmi/src/components/Balance.tsx
new file mode 100644
index 00000000..a07afca1
--- /dev/null
+++ b/code/wagmi/src/components/Balance.tsx
@@ -0,0 +1,9 @@
+import { useBalance } from 'wagmi';
+
+export function Balance() {
+ const balance = useBalance({
+ address: '0xBC989fDe9e54cAd2aB4392Af6dF60f04873A033A',
+ });
+
+ return {balance &&
Balance: {balance.data?.value.toString()}
}
;
+}
diff --git a/code/wagmi/src/components/BalanceTS.tsx b/code/wagmi/src/components/BalanceTS.tsx
new file mode 100644
index 00000000..ea0da6f1
--- /dev/null
+++ b/code/wagmi/src/components/BalanceTS.tsx
@@ -0,0 +1,18 @@
+import { fetchBalance } from '@/utils/balance';
+import { useState } from 'react';
+
+export function BalanceTS() {
+ const [balance, setBalance] = useState();
+
+ const updateBalance = async () => {
+ const newBalance = await fetchBalance();
+ setBalance(newBalance);
+ };
+
+ return (
+
+
Update Balance
+ {balance &&
Balance: {balance.toString()}
}
+
+ );
+}
diff --git a/code/wagmi/src/components/Block.tsx b/code/wagmi/src/components/Block.tsx
new file mode 100644
index 00000000..66c5e918
--- /dev/null
+++ b/code/wagmi/src/components/Block.tsx
@@ -0,0 +1,7 @@
+import { useBlockNumber } from 'wagmi';
+
+export function Block() {
+ const block = useBlockNumber();
+
+ return {block &&
Block: {block.data?.toString()}
}
;
+}
diff --git a/code/wagmi/src/components/BlockTS.tsx b/code/wagmi/src/components/BlockTS.tsx
new file mode 100644
index 00000000..1ebefbfc
--- /dev/null
+++ b/code/wagmi/src/components/BlockTS.tsx
@@ -0,0 +1,18 @@
+import { fetchLatestBlockNumber } from '@/utils/block';
+import { useState } from 'react';
+
+export function BlockTS() {
+ const [block, setBlock] = useState();
+
+ const updateBlock = async () => {
+ const newBlock = await fetchLatestBlockNumber();
+ setBlock(newBlock);
+ };
+
+ return (
+
+
Update Block
+ {block &&
Block: {block.toString()}
}
+
+ );
+}
diff --git a/code/wagmi/src/components/ConnectWallet.tsx b/code/wagmi/src/components/ConnectWallet.tsx
new file mode 100644
index 00000000..12a5e452
--- /dev/null
+++ b/code/wagmi/src/components/ConnectWallet.tsx
@@ -0,0 +1,12 @@
+import { injected } from '@wagmi/connectors';
+import { useConnect } from 'wagmi';
+
+export function ConnectWallet() {
+ const { connect } = useConnect();
+
+ return (
+
+ connect({ connector: injected() })}>Connect Wallet
+
+ );
+}
diff --git a/code/wagmi/src/components/ConnectWalletTS.tsx b/code/wagmi/src/components/ConnectWalletTS.tsx
new file mode 100644
index 00000000..54cf2c53
--- /dev/null
+++ b/code/wagmi/src/components/ConnectWalletTS.tsx
@@ -0,0 +1,9 @@
+import { connectWallet } from '@/utils/connect';
+
+export function ConnectWalletTS() {
+ return (
+
+ Connect Wallet
+
+ );
+}
diff --git a/code/wagmi/src/components/ReadContract.tsx b/code/wagmi/src/components/ReadContract.tsx
new file mode 100644
index 00000000..3e785d42
--- /dev/null
+++ b/code/wagmi/src/components/ReadContract.tsx
@@ -0,0 +1,67 @@
+import { useState } from 'react';
+import type { Address, BaseError } from 'viem';
+import { useReadContract } from 'wagmi';
+import * as erc20TokenABI from '../../../frontend-paymaster/contracts/artifacts-zk/contracts/erc20/MyERC20Token.sol/MyERC20Token.json';
+
+const CONTRACT_ADDRESS = '0x9c1a3d7C98dBF89c7f5d167F2219C29c2fe775A7';
+
+export function ReadContract() {
+ return (
+
+ );
+}
+
+function TotalSupply() {
+ const { data, isRefetching, refetch } = useReadContract({
+ abi: erc20TokenABI.abi,
+ address: CONTRACT_ADDRESS,
+ functionName: 'totalSupply',
+ });
+
+ console.log('data', data);
+
+ return (
+
+ Total Supply: {data?.toString()}
+ refetch()}
+ style={{ marginLeft: 4 }}
+ >
+ {isRefetching ? 'loading...' : 'refetch'}
+
+
+ );
+}
+
+function BalanceOf() {
+ const [address, setAddress] = useState('0xBC989fDe9e54cAd2aB4392Af6dF60f04873A033A');
+ const { data, error, isLoading, isSuccess } = useReadContract({
+ abi: erc20TokenABI.abi,
+ address: CONTRACT_ADDRESS,
+ functionName: 'balanceOf',
+ args: [address],
+ });
+
+ const [value, setValue] = useState(address);
+
+ return (
+
+ Token balance: {isSuccess && data?.toString()}
+
setValue(e.target.value)}
+ placeholder="wallet address"
+ style={{ marginLeft: 4 }}
+ value={value}
+ />
+
setAddress(value as Address)}>{isLoading ? 'fetching...' : 'fetch'}
+ {error &&
{(error as BaseError).shortMessage}
}
+
+ );
+}
diff --git a/code/wagmi/src/components/ReadContractTS.tsx b/code/wagmi/src/components/ReadContractTS.tsx
new file mode 100644
index 00000000..fb2a75c3
--- /dev/null
+++ b/code/wagmi/src/components/ReadContractTS.tsx
@@ -0,0 +1,24 @@
+import { readERC20Contract } from '@/utils/read';
+import { useState } from 'react';
+
+export function ReadContractTS() {
+ const [data, setData] = useState();
+
+ async function updateTotalSupply() {
+ const supply = await readERC20Contract('totalSupply');
+ const newData = supply as bigint;
+ setData(newData.toString());
+ }
+
+ return (
+
+ {data &&
Total Supply: {data?.toString()}
}
+
+ Update Total Supply
+
+
+ );
+}
diff --git a/code/wagmi/src/components/SendTx.tsx b/code/wagmi/src/components/SendTx.tsx
new file mode 100644
index 00000000..be46fff2
--- /dev/null
+++ b/code/wagmi/src/components/SendTx.tsx
@@ -0,0 +1,37 @@
+import { parseEther } from 'viem';
+import { useSendTransaction } from 'wagmi';
+
+export function SendTx() {
+ const { sendTransaction, isError, isPending, isSuccess, data, error } = useSendTransaction();
+
+ return (
+ <>
+
+
+ {isPending && Transaction pending...
}
+ {isSuccess && Transaction Hash: {data}
}
+ {isError && Error: {error?.message}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/SendTxPrepared.tsx b/code/wagmi/src/components/SendTxPrepared.tsx
new file mode 100644
index 00000000..1cb458fb
--- /dev/null
+++ b/code/wagmi/src/components/SendTxPrepared.tsx
@@ -0,0 +1,49 @@
+import { useState } from 'react';
+import { parseEther } from 'viem';
+import { usePrepareTransactionRequest, useSendTransaction } from 'wagmi';
+
+export function SendTxPrepared() {
+ const [to, setTo] = useState<`0x${string}`>();
+ const [value, setValue] = useState('0.0');
+
+ const { data: txRequest } = usePrepareTransactionRequest({
+ to,
+ value: parseEther(value as `${number}`),
+ });
+
+ const { sendTransaction, isError, isPending, isSuccess, data, error } = useSendTransaction();
+
+ return (
+ <>
+
+
+ {isPending && Transaction pending...
}
+ {isSuccess && Transaction Hash: {data}
}
+ {isError && Error: {error?.message}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/SendTxPreparedTS.tsx b/code/wagmi/src/components/SendTxPreparedTS.tsx
new file mode 100644
index 00000000..5efe18b5
--- /dev/null
+++ b/code/wagmi/src/components/SendTxPreparedTS.tsx
@@ -0,0 +1,44 @@
+import { prepareTx } from '@/utils/prepareTx';
+import { useState } from 'react';
+import { config } from '../../wagmi-config';
+import { sendTransaction } from '@wagmi/core';
+
+export function SendTxPreparedTS() {
+ const [data, setData] = useState();
+ const [to, setTo] = useState<`0x${string}`>();
+ const [value, setValue] = useState('0.0');
+
+ return (
+ <>
+
+
+ {data && Transaction Hash: {data}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/SendTxTS.tsx b/code/wagmi/src/components/SendTxTS.tsx
new file mode 100644
index 00000000..17d64b94
--- /dev/null
+++ b/code/wagmi/src/components/SendTxTS.tsx
@@ -0,0 +1,32 @@
+import { sendTx } from '@/utils/sendTx';
+import { useState } from 'react';
+
+export function SendTxTS() {
+ const [data, setData] = useState();
+ return (
+ <>
+
+
+ {data && Transaction Hash: {data}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/ShowConnectors.tsx b/code/wagmi/src/components/ShowConnectors.tsx
new file mode 100644
index 00000000..8a9a2ac7
--- /dev/null
+++ b/code/wagmi/src/components/ShowConnectors.tsx
@@ -0,0 +1,19 @@
+import { connectWallet } from '@/utils/connect';
+import { useConnectors } from 'wagmi';
+
+export function ShowConnectors() {
+ const connectors = useConnectors();
+
+ return (
+
+ {connectors.map((connector) => (
+
+ {connector.name}
+
+ ))}
+
+ );
+}
diff --git a/code/wagmi/src/components/ShowConnectorsTS.tsx b/code/wagmi/src/components/ShowConnectorsTS.tsx
new file mode 100644
index 00000000..ca74978d
--- /dev/null
+++ b/code/wagmi/src/components/ShowConnectorsTS.tsx
@@ -0,0 +1,19 @@
+import { connectWallet } from '@/utils/connect';
+import { fetchConnectors } from '@/utils/connectors';
+
+export function ShowConnectorsTS() {
+ const connectors = fetchConnectors();
+
+ return (
+
+ {connectors.map((connector) => (
+
+ {connector.name}
+
+ ))}
+
+ );
+}
diff --git a/code/wagmi/src/components/SignMessage.tsx b/code/wagmi/src/components/SignMessage.tsx
new file mode 100644
index 00000000..09d181f7
--- /dev/null
+++ b/code/wagmi/src/components/SignMessage.tsx
@@ -0,0 +1,54 @@
+import { useEffect, useState } from 'react';
+import { type Address, recoverMessageAddress } from 'viem';
+import { useSignMessage } from 'wagmi';
+
+export function SignMessage() {
+ const [recoveredAddress, setRecoveredAddress] = useState();
+ const { data: signature, variables, error, isPending, signMessage } = useSignMessage();
+
+ useEffect(() => {
+ (async () => {
+ if (variables?.message && signature) {
+ const recoveredAddress = await recoverMessageAddress({
+ message: variables?.message,
+ signature,
+ });
+ setRecoveredAddress(recoveredAddress);
+ }
+ })();
+ }, [signature, variables?.message]);
+
+ return (
+ <>
+
+
+ {signature && (
+
+
Signature: {signature}
+
Recovered address: {recoveredAddress}
+
+ )}
+ {error && Error: {error?.message}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/SignMessageTS.tsx b/code/wagmi/src/components/SignMessageTS.tsx
new file mode 100644
index 00000000..22851d33
--- /dev/null
+++ b/code/wagmi/src/components/SignMessageTS.tsx
@@ -0,0 +1,30 @@
+import { getSignedMessage } from '@/utils/message';
+import { useState } from 'react';
+
+export function SignMessageTS() {
+ const [data, setData] = useState();
+
+ return (
+ <>
+
+
+ {data && Signature: {data}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/SignTypedData.tsx b/code/wagmi/src/components/SignTypedData.tsx
new file mode 100644
index 00000000..e19deb85
--- /dev/null
+++ b/code/wagmi/src/components/SignTypedData.tsx
@@ -0,0 +1,42 @@
+import { useSignTypedData } from 'wagmi';
+
+export function SignTypedData() {
+ const { signTypedData, data } = useSignTypedData();
+
+ return (
+ <>
+
+ signTypedData({
+ types: {
+ Person: [
+ { name: 'name', type: 'string' },
+ { name: 'wallet', type: 'address' },
+ ],
+ Mail: [
+ { name: 'from', type: 'Person' },
+ { name: 'to', type: 'Person' },
+ { name: 'contents', type: 'string' },
+ ],
+ },
+ primaryType: 'Mail',
+ message: {
+ from: {
+ name: 'Cow',
+ wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
+ },
+ to: {
+ name: 'Bob',
+ wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
+ },
+ contents: 'Hello, Bob!',
+ },
+ })
+ }
+ >
+ Sign message
+
+ {data &&
Signature: {data}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/SignTypedDataTS.tsx b/code/wagmi/src/components/SignTypedDataTS.tsx
new file mode 100644
index 00000000..5335848a
--- /dev/null
+++ b/code/wagmi/src/components/SignTypedDataTS.tsx
@@ -0,0 +1,44 @@
+import { getSignedTypedData } from '@/utils/signTyped';
+import { useState } from 'react';
+
+export function SignTypedDataTS() {
+ const [signature, setSignature] = useState();
+
+ return (
+ <>
+ {
+ const sig = await getSignedTypedData({
+ types: {
+ Person: [
+ { name: 'name', type: 'string' },
+ { name: 'wallet', type: 'address' },
+ ],
+ Mail: [
+ { name: 'from', type: 'Person' },
+ { name: 'to', type: 'Person' },
+ { name: 'contents', type: 'string' },
+ ],
+ },
+ primaryType: 'Mail',
+ message: {
+ from: {
+ name: 'Cow',
+ wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
+ },
+ to: {
+ name: 'Bob',
+ wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
+ },
+ contents: 'Hello, Bob!',
+ },
+ });
+ setSignature(sig);
+ }}
+ >
+ Sign message
+
+ {signature &&
Signature: {signature}
}
+ >
+ );
+}
diff --git a/code/wagmi/src/components/WriteContract.tsx b/code/wagmi/src/components/WriteContract.tsx
new file mode 100644
index 00000000..e5dcd1b1
--- /dev/null
+++ b/code/wagmi/src/components/WriteContract.tsx
@@ -0,0 +1,34 @@
+import { useState } from 'react';
+import { type BaseError, useWriteContract } from 'wagmi';
+import * as greeterABI from '../../../frontend-paymaster/contracts/artifacts-zk/contracts/Greeter.sol/Greeter.json';
+
+const CONTRACT_ADDRESS = '0xCeAB1fc2693930bbad33024D270598c620D7A52B';
+
+export function WriteContract() {
+ const [greeting, setGreeting] = useState();
+ const { writeContract, isError, isPending, isSuccess, data, error } = useWriteContract();
+
+ async function updateGreeting() {
+ if (!greeting) return;
+ writeContract({
+ abi: greeterABI.abi,
+ address: CONTRACT_ADDRESS,
+ functionName: 'setGreeting',
+ args: [greeting],
+ });
+ }
+
+ return (
+
+
setGreeting(e.target.value)}
+ placeholder="Hello, Zeek!"
+ style={{ marginLeft: 4 }}
+ value={greeting}
+ />
+
{isPending ? '...Pending' : 'Update Greeting'}
+ {isError &&
{(error as BaseError).shortMessage}
}
+ {isSuccess &&
Transaction hash: {data}
}
+
+ );
+}
diff --git a/code/wagmi/src/components/WriteContractTS.tsx b/code/wagmi/src/components/WriteContractTS.tsx
new file mode 100644
index 00000000..cae8ab14
--- /dev/null
+++ b/code/wagmi/src/components/WriteContractTS.tsx
@@ -0,0 +1,26 @@
+import { useState } from 'react';
+import { writeToGreeterContract } from '../utils/write';
+
+export function WriteContractTS() {
+ const [greeting, setGreeting] = useState();
+ const [data, setData] = useState();
+
+ async function updateGreeting() {
+ if (!greeting) return;
+ const txData = await writeToGreeterContract(greeting);
+ setData(txData as string);
+ }
+
+ return (
+
+
setGreeting(e.target.value)}
+ placeholder="Hello, Zeek!"
+ style={{ marginLeft: 4 }}
+ value={greeting}
+ />
+
Update Greeting
+ {data &&
Transaction hash: {data}
}
+
+ );
+}
diff --git a/code/wagmi/src/pages/_app.tsx b/code/wagmi/src/pages/_app.tsx
new file mode 100644
index 00000000..0b5cff4f
--- /dev/null
+++ b/code/wagmi/src/pages/_app.tsx
@@ -0,0 +1,16 @@
+import type { AppProps } from 'next/app';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { WagmiProvider } from 'wagmi';
+import { config } from '../../wagmi-config';
+
+const queryClient = new QueryClient();
+
+export default function App({ Component, pageProps }: AppProps) {
+ return (
+
+
+ ;
+
+
+ );
+}
diff --git a/code/wagmi/src/pages/_document.tsx b/code/wagmi/src/pages/_document.tsx
new file mode 100644
index 00000000..e1e9cbbb
--- /dev/null
+++ b/code/wagmi/src/pages/_document.tsx
@@ -0,0 +1,13 @@
+import { Html, Head, Main, NextScript } from 'next/document';
+
+export default function Document() {
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/code/wagmi/src/pages/index.tsx b/code/wagmi/src/pages/index.tsx
new file mode 100644
index 00000000..6ebd9cd2
--- /dev/null
+++ b/code/wagmi/src/pages/index.tsx
@@ -0,0 +1,82 @@
+import Head from 'next/head';
+import { useEffect, useState } from 'react';
+import { ConnectWalletTS } from '@/components/ConnectWalletTS';
+import { ConnectWallet } from '@/components/ConnectWallet';
+import { ShowConnectors } from '@/components/ShowConnectors';
+import { ShowConnectorsTS } from '@/components/ShowConnectorsTS';
+import { Account } from '@/components/Account';
+import { AccountTS } from '@/components/AccountTS';
+import { Balance } from '@/components/Balance';
+import { BalanceTS } from '@/components/BalanceTS';
+import { Block } from '@/components/Block';
+import { BlockTS } from '@/components/BlockTS';
+import { SendTx } from '@/components/SendTx';
+import { SendTxTS } from '@/components/SendTxTS';
+import { SendTxPrepared } from '@/components/SendTxPrepared';
+import { SendTxPreparedTS } from '@/components/SendTxPreparedTS';
+import { SignMessage } from '@/components/SignMessage';
+import { SignMessageTS } from '@/components/SignMessageTS';
+import { SignTypedData } from '@/components/SignTypedData';
+import { SignTypedDataTS } from '@/components/SignTypedDataTS';
+import { ReadContract } from '@/components/ReadContract';
+import { ReadContractTS } from '@/components/ReadContractTS';
+import { WriteContract } from '@/components/WriteContract';
+import { WriteContractTS } from '@/components/WriteContractTS';
+
+export default function Home() {
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ setMounted(true);
+ }, []);
+
+ return (
+ <>
+
+ Wagmi ZKsync Demo
+
+
+
+
+
+
+ {mounted && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+ >
+ );
+}
diff --git a/code/wagmi/src/utils/account.ts b/code/wagmi/src/utils/account.ts
new file mode 100644
index 00000000..dd711bc2
--- /dev/null
+++ b/code/wagmi/src/utils/account.ts
@@ -0,0 +1,7 @@
+import { getAccount } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+
+export function fetchAccount() {
+ const { address } = getAccount(config);
+ return address;
+}
diff --git a/code/wagmi/src/utils/balance.ts b/code/wagmi/src/utils/balance.ts
new file mode 100644
index 00000000..ce0ac113
--- /dev/null
+++ b/code/wagmi/src/utils/balance.ts
@@ -0,0 +1,8 @@
+import { getBalance } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+
+export async function fetchBalance() {
+ const address = '0xBC989fDe9e54cAd2aB4392Af6dF60f04873A033A';
+ const balance = await getBalance(config, { address });
+ return balance.value;
+}
diff --git a/code/wagmi/src/utils/block.ts b/code/wagmi/src/utils/block.ts
new file mode 100644
index 00000000..1357ffd5
--- /dev/null
+++ b/code/wagmi/src/utils/block.ts
@@ -0,0 +1,7 @@
+import { getBlockNumber } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+
+export async function fetchLatestBlockNumber() {
+ const blockNumber = await getBlockNumber(config);
+ return blockNumber;
+}
diff --git a/code/wagmi/src/utils/connect.ts b/code/wagmi/src/utils/connect.ts
new file mode 100644
index 00000000..7dc8adfc
--- /dev/null
+++ b/code/wagmi/src/utils/connect.ts
@@ -0,0 +1,11 @@
+import { connect } from '@wagmi/core';
+import { injected } from '@wagmi/connectors';
+import { config } from '../../wagmi-config';
+
+export async function connectWallet() {
+ try {
+ await connect(config, { connector: injected() });
+ } catch (error) {
+ console.error('ERROR CONNECTING:', error);
+ }
+}
diff --git a/code/wagmi/src/utils/connectors.ts b/code/wagmi/src/utils/connectors.ts
new file mode 100644
index 00000000..1a923e38
--- /dev/null
+++ b/code/wagmi/src/utils/connectors.ts
@@ -0,0 +1,7 @@
+import { getConnectors } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+
+export function fetchConnectors() {
+ const connectors = getConnectors(config);
+ return connectors;
+}
diff --git a/code/wagmi/src/utils/message.ts b/code/wagmi/src/utils/message.ts
new file mode 100644
index 00000000..d97a716a
--- /dev/null
+++ b/code/wagmi/src/utils/message.ts
@@ -0,0 +1,7 @@
+import { signMessage } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+
+export async function getSignedMessage(message: string) {
+ const signature = await signMessage(config, { message });
+ return signature;
+}
diff --git a/code/wagmi/src/utils/prepareTx.ts b/code/wagmi/src/utils/prepareTx.ts
new file mode 100644
index 00000000..5854fd87
--- /dev/null
+++ b/code/wagmi/src/utils/prepareTx.ts
@@ -0,0 +1,12 @@
+import { prepareTransactionRequest } from '@wagmi/core';
+import { parseEther } from 'viem';
+import { config } from '../../wagmi-config';
+
+export async function prepareTx(to: `0x${string}`, value: `${number}`) {
+ const tx = await prepareTransactionRequest(config, {
+ to,
+ value: parseEther(value),
+ });
+
+ return tx;
+}
diff --git a/code/wagmi/src/utils/read.ts b/code/wagmi/src/utils/read.ts
new file mode 100644
index 00000000..1327207c
--- /dev/null
+++ b/code/wagmi/src/utils/read.ts
@@ -0,0 +1,14 @@
+import { readContract } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+import * as erc20TokenABI from '../../../frontend-paymaster/contracts/artifacts-zk/contracts/erc20/MyERC20Token.sol/MyERC20Token.json';
+
+const CONTRACT_ADDRESS = '0x9c1a3d7C98dBF89c7f5d167F2219C29c2fe775A7';
+
+export async function readERC20Contract(functionName: string) {
+ const data = await readContract(config, {
+ abi: erc20TokenABI.abi,
+ address: CONTRACT_ADDRESS,
+ functionName: functionName,
+ });
+ return data;
+}
diff --git a/code/wagmi/src/utils/sendTx.ts b/code/wagmi/src/utils/sendTx.ts
new file mode 100644
index 00000000..dd588e82
--- /dev/null
+++ b/code/wagmi/src/utils/sendTx.ts
@@ -0,0 +1,12 @@
+import { sendTransaction } from '@wagmi/core';
+import { parseEther } from 'viem';
+import { config } from '../../wagmi-config';
+
+export async function sendTx(address: `0x${string}`, value: `${number}`) {
+ const result = await sendTransaction(config, {
+ to: address,
+ value: parseEther(value),
+ });
+
+ return result;
+}
diff --git a/code/wagmi/src/utils/signTyped.ts b/code/wagmi/src/utils/signTyped.ts
new file mode 100644
index 00000000..d085471d
--- /dev/null
+++ b/code/wagmi/src/utils/signTyped.ts
@@ -0,0 +1,7 @@
+import { signTypedData, type SignTypedDataParameters } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+
+export async function getSignedTypedData(data: SignTypedDataParameters) {
+ const signature = await signTypedData(config, data);
+ return signature;
+}
diff --git a/code/wagmi/src/utils/write.ts b/code/wagmi/src/utils/write.ts
new file mode 100644
index 00000000..335c7481
--- /dev/null
+++ b/code/wagmi/src/utils/write.ts
@@ -0,0 +1,15 @@
+import { readContract } from '@wagmi/core';
+import { config } from '../../wagmi-config';
+import * as greeterABI from '../../../frontend-paymaster/contracts/artifacts-zk/contracts/Greeter.sol/Greeter.json';
+
+const CONTRACT_ADDRESS = '0xCeAB1fc2693930bbad33024D270598c620D7A52B';
+
+export async function writeToGreeterContract(greeting: string) {
+ const data = await readContract(config, {
+ abi: greeterABI.abi,
+ address: CONTRACT_ADDRESS,
+ functionName: 'setGreeting',
+ args: [greeting],
+ });
+ return data;
+}
diff --git a/code/wagmi/tsconfig.json b/code/wagmi/tsconfig.json
new file mode 100644
index 00000000..572b7ad3
--- /dev/null
+++ b/code/wagmi/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+ "exclude": ["node_modules"]
+}
diff --git a/code/wagmi/wagmi-config.ts b/code/wagmi/wagmi-config.ts
new file mode 100644
index 00000000..fd6717ab
--- /dev/null
+++ b/code/wagmi/wagmi-config.ts
@@ -0,0 +1,18 @@
+import { http, createConfig } from '@wagmi/core';
+import { zksync, zksyncSepoliaTestnet, zksyncInMemoryNode, zksyncLocalNode } from '@wagmi/core/chains';
+import { walletConnect } from '@wagmi/connectors';
+
+export const config = createConfig({
+ chains: [zksync, zksyncSepoliaTestnet, zksyncInMemoryNode, zksyncLocalNode],
+ connectors: [
+ walletConnect({
+ projectId: 'd4a7167a6eed6a53c8364631aaeca861',
+ }),
+ ],
+ transports: {
+ [zksync.id]: http(),
+ [zksyncSepoliaTestnet.id]: http(),
+ [zksyncInMemoryNode.id]: http(),
+ [zksyncLocalNode.id]: http(),
+ },
+});
diff --git a/content/tutorials/guide-viem/_dir.yml b/content/tutorials/guide-viem/_dir.yml
index e2412e89..035f39a0 100644
--- a/content/tutorials/guide-viem/_dir.yml
+++ b/content/tutorials/guide-viem/_dir.yml
@@ -8,6 +8,7 @@ github_repo: https://github.com/matter-labs
tags:
- guide
- viem
+ - frontend
summary: This page will explain how to use the viem/zksync plugin to interact with ZKsync.
description:
This guide outlines how to use the ZKsync viem plugin to interact with ZKsync and use specific actions like sending
diff --git a/content/tutorials/guide-wagmi/10.index.md b/content/tutorials/guide-wagmi/10.index.md
index 4da524ce..c2197a85 100644
--- a/content/tutorials/guide-wagmi/10.index.md
+++ b/content/tutorials/guide-wagmi/10.index.md
@@ -11,507 +11,212 @@ For setup instructions, consult the official documentation [here](https://wagmi.
Wagmi hooks do not yet support Paymasters and native Account Abstraction; development is in progress.
::
+## Project Setup
+
+### Installing Dependencies
+
+::code-group
+
+```bash [npm]
+npm install @wagmi/core @wagmi/connectors viem@2.x
+```
+
+```bash [yarn]
+yarn add @wagmi/core @wagmi/connectors viem@2.x
+```
+
+```bash [pnpm]
+pnpm add @wagmi/core @wagmi/connectors viem@2.x
+```
+
+```bash [bun]
+bun add @wagmi/core @wagmi/connectors viem@2.x
+```
+
+::
+
+For React projects, you can also make use of the `wagmi` package:
+
+::code-group
+
+```bash [npm]
+npm install wagmi viem@2.x @tanstack/react-query
+```
+
+```bash [yarn]
+yarn add wagmi viem@2.x @tanstack/react-query
+```
+
+```bash [pnpm]
+pnpm add wagmi viem@2.x @tanstack/react-query
+```
+
+```bash [bun]
+bun add wagmi viem@2.x @tanstack/react-query
+```
+
+::
+
+### Configuration
+
+Make a file called `wagmi-config.ts` and configure your preferred ZKsync network.
+
+```ts [wagmi-config.ts]
+:code-import{filePath="wagmi/wagmi-config.ts"}
+```
+
Here are some common actions:
## Connect Wallet
-
-```typescript
-import { w3mConnectors, w3mProvider } from "@web3modal/ethereum";
-import { configureChains, createConfig } from "wagmi";
-import { zkSync, zkSyncTestnet } from "wagmi/chains";
-
-export const walletConnectProjectId = "d4a7167a6eed6a53c8364631aaeca861";
-
-const { chains, publicClient, webSocketPublicClient } = configureChains(
- [zkSync, ...(import.meta.env?.MODE === "development" ? [zkSyncTestnet] : [])],
- [w3mProvider({ projectId: walletConnectProjectId })]
-);
-
-export const config = createConfig({
- autoConnect: true,
- connectors: w3mConnectors({
- chains,
- projectId: walletConnectProjectId,
- version: 2,
- }),
- publicClient,
- webSocketPublicClient,
-});
-
-export { chains };
+
+### `connect` Method
+
+```jsx [connect.ts]
+:code-import{filePath="wagmi/src/utils/connect.ts"}
```
-
+
+### `useConnect` Hook
+
+```jsx [ConnectWallet.tsx]
+:code-import{filePath="wagmi/src/components/ConnectWallet.tsx"}
+```
+
## Display Wallet Options
-```typescript
-import { useConnect } from "wagmi";
-
-export function WalletOptions() {
- const { connect, connectors, error, isLoading, pendingConnector } = useConnect();
- console.log(connectors);
-
- return (
-
- {connectors.map((connector) => (
-
connect({ connector })}>
- {connector.name}
- {!connector.ready && " (unsupported)"}
- {isLoading && connector.id === pendingConnector?.id && " (connecting)"}
-
- ))}
-
- {error &&
{error.message}
}
-
- );
-}
+### `getConnectors` Method
+
+```ts [connectors.ts]
+:code-import{filePath="wagmi/src/utils/connectors.ts"}
+```
+
+### `useConnectors` Hook
+
+```jsx [ShowConnectors.tsx]
+:code-import{filePath="wagmi/src/components/ShowConnectors.tsx"}
```
## Fetch Account
-```typescript
-import { useAccount } from "wagmi";
+### `getAccount` Method
-export function Account() {
- const { address } = useAccount();
+```ts [account.ts]
+:code-import{filePath="wagmi/src/utils/account.ts"}
+```
- return {address}
;
-}
+### `useAccount` Hook
+
+```jsx [Account.tsx]
+:code-import{filePath="wagmi/src/components/Account.tsx"}
```
## Fetch Balance
-```typescript
-import { useState } from "react";
-import type { Address } from "wagmi";
-import { useAccount, useBalance } from "wagmi";
-
-export function Balance() {
- return (
- <>
-
-
-
-
-
- >
- );
-}
-
-export function AccountBalance() {
- const { address } = useAccount();
- const { data, refetch } = useBalance({
- address,
- watch: true,
- });
-
- return (
-
- {data?.formatted}
- refetch()}>refetch
-
- );
-}
-
-export function FindBalance() {
- const [address, setAddress] = useState("");
- const { data, isLoading, refetch } = useBalance({
- address: address as Address,
- });
-
- const [value, setValue] = useState("");
-
- return (
-
- Find balance:
setValue(e.target.value)} placeholder="wallet address" value={value} />
-
(value === address ? refetch() : setAddress(value))}>{isLoading ? "fetching..." : "fetch"}
-
{data?.formatted}
-
- );
-}
+### `getBalance` Method
+
+```ts [balance.ts]
+:code-import{filePath="wagmi/src/utils/balance.ts"}
+```
+
+### `useBalance` Hook
+
+```jsx [Balance.tsx]
+:code-import{filePath="wagmi/src/components/Balance.tsx"}
```
## Fetch Block Number
-```typescript
-import { useBlockNumber } from "wagmi";
+### `getBlockNumber` Method
-export function BlockNumber() {
- const { data } = useBlockNumber({ watch: true });
- return {data?.toString()}
;
-}
+```ts [block.ts]
+:code-import{filePath="wagmi/src/utils/block.ts"}
+```
+
+### `useBlockNumber` Hook
+
+```jsx [Block.tsx]
+:code-import{filePath="wagmi/src/components/Block.tsx"}
```
## Send Transaction
-```typescript
-import { parseEther } from "viem";
-import { useSendTransaction, useWaitForTransaction } from "wagmi";
-
-import { stringify } from "../utils/stringify";
-
-export function SendTransaction() {
- const { data, error, isLoading, isError, sendTransaction } = useSendTransaction();
- const { data: receipt, isLoading: isPending, isSuccess } = useWaitForTransaction({ hash: data?.hash });
-
- return (
- <>
-
-
- {isLoading && Check wallet...
}
- {isPending && Transaction pending...
}
- {isSuccess && (
- <>
- Transaction Hash: {data?.hash}
-
- Transaction Receipt:
{stringify(receipt, null, 2)}
-
- >
- )}
- {isError && Error: {error?.message}
}
- >
- );
-}
+### `sendTransaction` Method
+
+```ts [sendTx.ts]
+:code-import{filePath="wagmi/src/utils/sendTx.ts"}
+```
+
+### `useSendTransaction` Hook
+
+```jsx [SendTx.tsx]
+:code-import{filePath="wagmi/src/components/SendTx.tsx"}
```
## Send Transaction (Prepared)
-```typescript
-import { useState } from "react";
-import { parseEther, stringify } from "viem";
-import { usePrepareSendTransaction, useSendTransaction, useWaitForTransaction } from "wagmi";
-
-import { useDebounce } from "../hooks/useDebounce";
-
-export function SendTransactionPrepared() {
- const [to, setTo] = useState("");
- const debouncedTo = useDebounce(to);
-
- const [value, setValue] = useState("");
- const debouncedValue = useDebounce(value);
-
- const { config } = usePrepareSendTransaction({
- to: debouncedTo,
- value: debouncedValue ? parseEther(value as `${number}`) : undefined,
- enabled: Boolean(debouncedTo && debouncedValue),
- });
- const { data, error, isLoading, isError, sendTransaction } = useSendTransaction(config);
- const { data: receipt, isLoading: isPending, isSuccess } = useWaitForTransaction({ hash: data?.hash });
-
- return (
- <>
-
-
- {isLoading && Check wallet...
}
- {isPending && Transaction pending...
}
- {isSuccess && (
- <>
- Transaction Hash: {data?.hash}
-
- Transaction Receipt:
{stringify(receipt, null, 2)}
-
- >
- )}
- {isError && Error: {error?.message}
}
- >
- );
-}
+### `prepareTransactionRequest` Method
+
+```ts [prepareTx.ts]
+:code-import{filePath="wagmi/src/utils/prepareTx.ts"}
+```
+
+### `usePrepareTransactionRequest` Hook
+
+```jsx [SendTxPrepared.tsx]
+:code-import{filePath="wagmi/src/components/SendTxPrepared.tsx"}
```
## Sign Message
-```typescript
-import { useEffect, useState } from "react";
-import { recoverMessageAddress } from "viem";
-import { type Address, useSignMessage } from "wagmi";
-
-export function SignMessage() {
- const [recoveredAddress, setRecoveredAddress] = useState();
- const { data: signature, variables, error, isLoading, signMessage } = useSignMessage();
-
- useEffect(() => {
- (async () => {
- if (variables?.message && signature) {
- const recoveredAddress = await recoverMessageAddress({
- message: variables?.message,
- signature,
- });
- setRecoveredAddress(recoveredAddress);
- }
- })();
- }, [signature, variables?.message]);
-
- return (
- <>
-
-
- {signature && (
-
-
Signature: {signature}
-
Recovered address: {recoveredAddress}
-
- )}
- {error && Error: {error?.message}
}
- >
- );
-}
+### `signMessage` Method
+
+```ts [message.ts]
+:code-import{filePath="wagmi/src/utils/message.ts"}
+```
+
+### `useSignMessage` Hook
+
+```jsx [SignMessage.tsx]
+:code-import{filePath="wagmi/src/components/SignMessage.tsx"}
```
## Sign Typed Data
-```typescript
-import { useEffect, useState } from "react";
-import { recoverTypedDataAddress } from "viem";
-import { type Address, useSignTypedData } from "wagmi";
-
-const domain = {
- name: "Ether Mail",
- version: "1",
- chainId: 280 || 324,
- verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
-} as const;
-
-const types = {
- Person: [
- { name: "name", type: "string" },
- { name: "wallet", type: "address" },
- ],
- Mail: [
- { name: "from", type: "Person" },
- { name: "to", type: "Person" },
- { name: "contents", type: "string" },
- ],
-} as const;
-
-const message = {
- from: {
- name: "Cow",
- wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
- },
- to: {
- name: "Bob",
- wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
- },
- contents: "Hello, Bob!",
-} as const;
-
-export function SignTypedData() {
- const { data, error, isLoading, signTypedData } = useSignTypedData({
- domain,
- types,
- message,
- primaryType: "Mail",
- });
-
- const [recoveredAddress, setRecoveredAddress] = useState();
- useEffect(() => {
- if (!data) return;
- (async () => {
- setRecoveredAddress(
- await recoverTypedDataAddress({
- domain,
- types,
- message,
- primaryType: "Mail",
- signature: data,
- })
- );
- })();
- }, [data]);
-
- return (
- <>
- signTypedData()}>
- {isLoading ? "Check Wallet" : "Sign Message"}
-
-
- {data && (
-
-
Signature: {data}
-
Recovered address {recoveredAddress}
-
- )}
- {error && Error: {error?.message}
}
- >
- );
-}
+### `signTypedData` Method
+
+```ts [signTyped.ts]
+:code-import{filePath="wagmi/src/utils/signTyped.ts"}
+```
+
+### `useSignTypedData` Hook
+
+```jsx [SignTypedData.tsx]
+:code-import{filePath="wagmi/src/components/SignTypedData.tsx"}
```
## Read Contract
-```typescript
-import { useState } from "react";
-import { BaseError } from "viem";
-import { type Address, useContractRead } from "wagmi";
-
-import { erc20TokenABI } from "./contracts";
-
-export function ReadContract() {
- return (
-
- );
-}
-
-function TotalSupply() {
- const { data, isRefetching, refetch } = useContractRead({
- ...erc20TokenABI,
- functionName: "totalSupply",
- });
-
- return (
-
- Total Supply: {data?.toString()}
- refetch()} style={{ marginLeft: 4 }}>
- {isRefetching ? "loading..." : "refetch"}
-
-
- );
-}
-
-function BalanceOf() {
- const [address, setAddress] = useState("0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b");
- const { data, error, isLoading, isSuccess } = useContractRead({
- ...erc20TokenABI,
- functionName: "balanceOf",
- args: [address],
- enabled: Boolean(address),
- });
-
- const [value, setValue] = useState(address);
-
- return (
-
- Token balance: {isSuccess && data?.toString()}
-
setValue(e.target.value)} placeholder="wallet address" style={{ marginLeft: 4 }} value={value} />
-
setAddress(value as Address)}>{isLoading ? "fetching..." : "fetch"}
- {error &&
{(error as BaseError).shortMessage}
}
-
- );
-}
+### `readContract` Method
+
+```ts [signTyped.ts]
+:code-import{filePath="wagmi/src/utils/read.ts"}
```
-## Token
-
-```typescript
-import { useState } from "react";
-import { type Address, useToken } from "wagmi";
-
-export function Token() {
- const [address, setAddress] = useState("0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b");
- const { data, error, isError, isLoading, refetch } = useToken({ address });
-
- return (
- <>
-
- setAddress(e.target.value as Address)} placeholder="token address" value={address} />
- refetch()}>fetch
-
-
- {data && (
-
- {data.totalSupply?.formatted} {data.symbol}
-
- )}
- {isLoading && Fetching token...
}
- {isError && Error: {error?.message}
}
- >
- );
-}
+### `useReadContract` Hook
+
+```jsx [ReadContract.tsx]
+:code-import{filePath="wagmi/src/components/ReadContract.tsx"}
```
## Write Contract
-```typescript
-import { BaseError } from "viem";
-import { useContractWrite, useWaitForTransaction } from "wagmi";
-
-import { erc721Contract } from "./contracts";
-import { stringify } from "../utils/stringify";
-
-export function WriteContract() {
- const { write, data, error, isLoading, isError } = useContractWrite({
- ...erc721Contract,
- functionName: "mint",
- });
- const { data: receipt, isLoading: isPending, isSuccess } = useWaitForTransaction({ hash: data?.hash });
-
- return (
- <>
- Mint an NFT
-
-
- {isLoading && Check wallet...
}
- {isPending && Transaction pending...
}
- {isSuccess && (
- <>
- Transaction Hash: {data?.hash}
-
- Transaction Receipt:
{stringify(receipt, null, 2)}
-
- >
- )}
- {isError && {(error as BaseError)?.shortMessage}
}
- >
- );
-}
+### `writeContract` Method
+
+```ts [write.ts]
+:code-import{filePath="wagmi/src/utils/write.ts"}
+```
+
+### `useWriteContract` Hook
+
+```jsx [WriteContract.tsx]
+:code-import{filePath="wagmi/src/components/WriteContract.tsx"}
```
diff --git a/content/tutorials/guide-wagmi/_dir.yml b/content/tutorials/guide-wagmi/_dir.yml
index a4036575..4de6d2c1 100644
--- a/content/tutorials/guide-wagmi/_dir.yml
+++ b/content/tutorials/guide-wagmi/_dir.yml
@@ -7,6 +7,7 @@ github_repo: https://github.com/matter-labs
tags:
- guide
- wagmi
+ - frontend
summary: Learn how to use the Wagmi toolkit to create websites that interact with contracts on ZKsync
description:
This guide outlines how to use the wagmi library to create websites that interact with ZKsync contracts. We provide
diff --git a/content/tutorials/guide-walletconnect/_dir.yml b/content/tutorials/guide-walletconnect/_dir.yml
index 38d29c8f..86946ab4 100644
--- a/content/tutorials/guide-walletconnect/_dir.yml
+++ b/content/tutorials/guide-walletconnect/_dir.yml
@@ -7,6 +7,7 @@ github_repo: https://github.com/matter-labs
tags:
- guide
- walletconnect
+ - frontend
summary: Learn how to use WalletConnect to create React apps that interact with contracts on ZKsync.
description:
This guide outlines how to use WalletConnect and Web3Modal to create React apps that interact with contracts on ZKsync
diff --git a/content/tutorials/guide-web3js/_dir.yml b/content/tutorials/guide-web3js/_dir.yml
index a380720e..86329fe0 100644
--- a/content/tutorials/guide-web3js/_dir.yml
+++ b/content/tutorials/guide-web3js/_dir.yml
@@ -8,6 +8,7 @@ github_repo: https://github.com/ChainSafe
tags:
- guide
- web3.js
+ - frontend
summary:
This guide will teach you how to set up and use Web3.js to interact with ZKsync, leveraging the ZKsync Web3.js plugin.
description:
diff --git a/pages/tutorials/index.vue b/pages/tutorials/index.vue
index 65d63a9a..feef75b2 100644
--- a/pages/tutorials/index.vue
+++ b/pages/tutorials/index.vue
@@ -24,7 +24,7 @@ const allTags = computed(() => {
const uniqueTags = computed(() => [...new Set(allTags.value)]);
-const activeTag = ref(uniqueTags.value[0] || '');
+const activeTag = ref('');
const isExpanded = ref(false);
const defaultCount = 6;