Setup a Dapp easily with Wagmi, Viem and Web3Modal
As a Dapp developer, we always need to focus on connecting user wallet, getting user blockchain data (balance, block, hash,…) and of course calling smart contract functions. With these 3 tools your life will be much more easier. And your code base will be more elegant. Let take a look at these tools then build a simple Dapp with them. You can then use this project to build any kind of Dapp you need.
1. What’s wagmi, viem, web3Modal ?
Ok let’s get start….
2. But first, a little story
Before ethers, developer used to use web3js, an old school library which provided ability to work with blockchain. But the framework itself lack a lot of features for example it not support promise it use call back metrics for handling the asynchonous task it make the code really hard to read. After that, ethers came out, with a lot of nice features and promise base actions which make working with blockchain is much more easier. Then one day, my colleague tell me to check the wagmi library which provides a lot of react hooks to work with smart contract, getting balance, etc… instead of using directly ethers lib. Using ethers i need to save some information about blockchain connection (ex: user address, user balance, current network, ether provider,…) to redux for using it later or create a class to abstract the calling smart contract functions steps. But with wagmi i just need to call the provided hooks and dont need to think much. Wagmi is an abstraction level of ethers and now is viem. It has a lot of nice things but also some sides that i don’t like that i will mention when we code.
For a short conclusion, nowadays, we have a lot of tools and lib for build an elegant Dapp with js/ts Just chose anything you want then start your project.
3. Ok let’s go
3.1 Create project
yarn add viem wagmi @wagmi/core @web3modal/ethereum @web3modal/react
3.2 create wagmi client and setup web3Modal
First, we need a we need a wallet connect project id, visit: https://cloud.walletconnect.com/app create an account then create a project to get the project id
Now in App.tsx let setup wagmi and web3Modal to connect to the smart chain test net. At this step i highly recommend to read the three lib’s docs in section 1 of the blogs.
import { configureChains, createConfig, WagmiConfig } from "wagmi";
import { bscTestnet } from "wagmi/chains";
import {
EthereumClient,
w3mConnectors,
w3mProvider,
} from "@web3modal/ethereum";
import { Web3Modal } from "@web3modal/react";
import Dapp from "./Dapp";
const chains = [bscTestnet];
const projectId = "your-walletconnect-project-id";
const { publicClient } = configureChains(chains, [w3mProvider({ projectId })]);
const wagmiConfig = createConfig({
autoConnect: false,
connectors: w3mConnectors({ projectId, chains }),
publicClient,
});
const ethereumClient = new EthereumClient(wagmiConfig, chains);
function App() {
return (
<>
<WagmiConfig config={wagmiConfig}>
<Dapp />
</WagmiConfig>
<Web3Modal
projectId={projectId}
ethereumClient={ethereumClient}
defaultChain={bscTestnet}
/>
</>
);
}
export default App;
We get the bscTestNet config from wagmi pass it the config object along with the provider and client of the ethereum from web3Modal. Then in Jsx we wrap all of our component inside <WagmiConfig> component so all children components can use wagmi hook then init an web3Modal component at the end of the page.
领英推荐
3.3 Connect disconnect
import { useWeb3Modal } from "@web3modal/react";
import { useAccount, useDisconnect } from "wagmi";
const Dapp = () => {
const { open } = useWeb3Modal();
const { address, isConnected } = useAccount();
const { disconnect } = useDisconnect();
return (
<div>
<button onClick={isConnected ? disconnect : open}>
{isConnected ? address : "Connect to wallet"}
</button>
</div>
);
};
export default Dapp;
When you set up everything you just need to get the hook and use it really simple right ? Here is thhe result:
3.4 Calling the smart contract
Nice right now let’s try to call a smart contract. Let’s use this greet contract: https://testnet.bscscan.com/address/0xd24FcAedcc75dF6d9AE8581B9836e9781AE89fE8#writeContract
const {data: currentGreet = "", isLoading} = useContractRead({
abi: greeter_abi,
address: "0xd24FcAedcc75dF6d9AE8581B9836e9781AE89fE8",
functionName: "greet",
})
3.4 The @wagmi/core libarary
const [greeter, setGreeter] = useState("");
const updateGreet = async () => {
try {
//prepare transaction
const { request } = await prepareWriteContract({
address: "0xd24FcAedcc75dF6d9AE8581B9836e9781AE89fE8",
abi: greeter_abi,
functionName: "setGreeting",
args: ["Hello world"],
});
//send transaction to blockchain
const { hash } = await writeContract(request);
if (!hash) {
throw new Error("Transaction failed");
}
//wait for transaction to be mined
await waitForTransaction({ hash });
//refetch data
await reFetchGreeter();
} catch (err: any) {
console.log(err);
}
};
/***/
return (
/**/
<div>
<input
type="text"
value={greeter}
onChange={(e) => setGreeter(e.target.value)}
/>
<button onClick={updateGreet}>Update greet</button>
</div>
/**/
)
Here’s is a full Dapp component source code
import { useWeb3Modal } from "@web3modal/react";
import { useAccount, useContractRead, useDisconnect } from "wagmi";
import { greeter_abi } from "./geeting-abi";
import {
prepareWriteContract,
waitForTransaction,
writeContract,
} from "@wagmi/core";
import { useState } from "react";
const Dapp = () => {
const [greeter, setGreeter] = useState("");
const { open } = useWeb3Modal();
const { address, isConnected } = useAccount();
const { disconnect } = useDisconnect();
const { data: currentGreet = "", refetch: reFetchGreeter }: any =
useContractRead({
abi: greeter_abi,
address: "0xd24FcAedcc75dF6d9AE8581B9836e9781AE89fE8",
functionName: "greet",
});
const updateGreet = async () => {
try {
//prepare transaction
const { request } = await prepareWriteContract({
address: "0xd24FcAedcc75dF6d9AE8581B9836e9781AE89fE8",
abi: greeter_abi,
functionName: "setGreeting",
args: [greeter],
});
//send transaction to blockchain
const { hash } = await writeContract(request);
if (!hash) {
throw new Error("Transaction failed");
}
//wait for transaction to be mined
await waitForTransaction({ hash });
//refetch data
await reFetchGreeter();
alert("Transaction successful");
} catch (err: any) {
console.log(err);
}
};
return (
<div>
<button onClick={isConnected ? disconnect : open}>
{isConnected ? address : "Connect to wallet"}
</button>
<div>Current greet is {currentGreet}</div>
<div>
<input
type="text"
value={greeter}
onChange={(e) => setGreeter(e.target.value)}
/>
<button onClick={updateGreet}>Update greet</button>
</div>
</div>
);
};
export default Dapp;
4. Conclusion
With wagmi, viem the abstraction level compare to ethers or web3 is very high. That why they are very easy to use and power full. But base on your use case you need to chose which hooks, which functions to use. Thanks for reading and good luck when building your Dapp