Wagmi-Etherium hooks for React

Wagmi-Etherium hooks for React

In this article we'll be dealing with WAGMI, I'll break this article down into multiple parts covering a wide variety of topics in Wagmi.

My source of reference is the WAGMI Documentation. and chatGPT ")

If you find it challenging to read the documentation, don't worry I've got you covered, as I'll break it down into smaller and easy-to-understand chunks :)

Getting started

wagmi/code is a javascript library containing everything you need to start working with Ethereum. It makes it easy to "Connect Wallet," display ENS and balance information, sign messages, interact with contracts, and much more.
Installation

npm i @wagmi/core ethers

If you want to use @wagmi/core you need to install ethers. ethers is a peer dependency, which means it does not come bundled with the Wagmi/core library, you'll have to install it separately.

Configure Chains

Before we move forward I need you to understand a few things. A Provider is a software component that allows users to interact with a blockchain network.

Now let's configure the chain and provider for our given project.

import { configureChains } from '@wagmi/core'
import { publicProvider } from '@wagmi/core/providers/public'
import { avalanche, bsc, mainnet,goerli } from '@wagmi/core/chains'

const { chains, provider, webSocketProvider } = configureChains(
  [mainnet,bsc,avalanche,goerli],
  [alchemyProvider({ apiKey: 'yourAlchemyApiKey' })],
)

in place of alchemyProvider you can also have infuraProvider or if you want you can just use the publicProvider().

Now that we have configured the chains, we can create a client by passing the instances of the above to createClient.

Client is a framework agnostic (Vanilla JS) client that manages wallet connection state and configuration, such as auto-connection, connectors, and ethers providers.

const client = createClient({
  autoConnect: true,
  provider,
  webSocketProvider,
})

Now that that is done. we can fetch the address of who connected.

import { connect, fetchEnsName } from '@wagmi/core'
import { InjectedConnector } from '@wagmi/core/connectors/injected'

const { address } = await connect({
  connector: new InjectedConnector(),
})
const ensName = await fetchEnsName({ address })

Now you are probably wondering what is this InjectorConnector(), its basically a wallet that injects the Ethereum provider into the browser, such as metamask.

Lets look at an example where I need only metamask to connect to the webpage

import { mainnet, optimism, polygon } from '@wagmi/core/chains'
import { MetaMaskConnector } from '@wagmi/core/connectors/metaMask'

const connector = new MetaMaskConnector({
 chains: [mainnet, optimism, polygon],
  options: {
    shimDisconnect: true,
  }
})

Now before we proceed I need you to understand the following:
When shimDisconnect is set to true (which is the default behaviour), the connector will automatically disconnect from the wallet whenever the user logs out or closes the wallet window.
This is useful because it ensures that the connector does not continue to interact with the wallet after the user has disconnected, which could potentially cause security issues.

However, when shimDisconnect is set to false, the connector will continue to interact with the wallet even after the user logs out or closes the wallet window.
This can be useful in certain situations, such as when you want to continue to interact with the Ethereum network using the last-selected account, even if the user is no longer actively using the MetaMask wallet.

Actions

  • How do we connect?
    We've already discussed this above, following is the syntax:

      import { connect } from '@wagmi/core'
      import { InjectedConnector } from '@wagmi/core/connectors/injected'
    
      const result = await connect({
        connector: new InjectedConnector(),
      })
    
  • How do we disconnect?
    The action for disconnecting the connected account is as follows

      import { disconnect } from '@wagmi/core'
    
      await disconnect()
    
  • How do we FetchBalance?

      import { fetchBalance } from '@wagmi/core'
    
      const balance = await fetchBalance({
        address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
        formatUnits: 'ether' //default
      })
    
  • How do we fetch BlockNumber?

      import { fetchBlockNumber } from '@wagmi/core'
    
      const blockNumber = await fetchBlockNumber()
    
  • Given the ENS name, how do we fetch Address?

      import { fetchEnsAddress } from '@wagmi/core'
    
      const address = await fetchEnsAddress({
        name: 'xyz.eth',
      })
    
  • fetchEnsAvatar

      import { fetchEnsAvatar } from '@wagmi/core'
    
      const ensAvatar = await fetchEnsAvatar({
        address: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
      })
    
  • Fetch ENS Name

      import { fetchEnsName } from '@wagmi/core'
    
      const ensName = await fetchEnsName({
        address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
      })
    
  • How do we fetch network fee information?

      import { fetchFeeData } from '@wagmi/core'
    
      const feeData = await fetchFeeData({
        chainId: 1,
        formatUnits: 'gwei'
      })
    
  • Fetch the signer

      import { fetchSigner } from '@wagmi/core'
    
      const signer = await fetchSigner()
    
  • Ferch ERC20 token information

      import { fetchToken } from '@wagmi/core'
    
      const token = await fetchToken({
        address: '0xc18360217d8f7ab5e7c516566761ea12ce7f9d72',
      })
    
  • What if you want to know which account is connected to you're website

      import { getAccount } from '@wagmi/core'
    
      const account = getAccount()
    
  • Now say you want to play around with the functions of a contract, for that, first you need to create an instance of the contract

      import { getContract, getProvider } from '@wagmi/core'
    
      const provider = getProvider()
    
      const contract = getContract({
        address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
        abi: ensRegistryABI,
        signerOrProvider: provider,
      })
    
  • What if you have multiple functions you want to call at the start of the execution, in this case instead of calling them one at a time you can use multicall , you can also call functions from different contracts if you want.

      import { multicall } from '@wagmi/core'
    
      const data = await multicall({
        contracts: [
          {
            address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
            abi: mlootABI,
            functionName: 'getChest',
            args: [69],
          },
          {
            address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
            abi: mlootABI,
            functionName: 'getWaist',
            args: [69],
          },
        ],
      })
    
  • we are using the prepareSendTransaction function to create a transaction object, this object is passed to sendTransaction, which executes it.

      import { prepareSendTransaction, sendTransaction } from '@wagmi/core'
    
      const config = await prepareSendTransaction({
        request: {
          to: 'moxey.eth',
          value: parseEther('1'),
        },
      })
      const { hash } = await sendTransaction(config)
    
  • If you want to write to a contract, you follow the same as above, almost the same as above.

      import { prepareWriteContract, writeContract } from '@wagmi/core'
    
      const config = await prepareWriteContract({
        address: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
        abi: wagmigotchiABI,
        functionName: 'feed',
      })
      const { hash } = await writeContract(config)
    

    Now what if you have to send input with the function name, below is the syntax that shows you how to create a writeContract.

      import { prepareWriteContract } from '@wagmi/core'
    
      const config = await prepareWriteContract({
        address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
        abi: [
          {
            name: 'mint',
            type: 'function',
            stateMutability: 'nonpayable',
            inputs: [{ internalType: 'uint32', name: 'tokenId', type: 'uint32' }],
            outputs: [],
          },
        ],
        functionName: 'mint',
        args: [69],
      })
    

    Now what if the function is payable?

  •     import { prepareWriteContract } from '@wagmi/core'
    
        const { config } = await prepareWriteContract({
          address: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
          abi: wagmigotchiABI,
          functionName: 'feed',
          overrides: {
            from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
            value: ethers.utils.parseEther('0.01'),
          },
        })
    
  • Now that we have understood how to call a write function from a contract, let's understand how to read/call a function from a contract

      import { readContract } from '@wagmi/core'
    
      const data = await readContract({
        address: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
        abi: wagmigotchiABI,
        functionName: 'getHunger',
        args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'],
      })
    
  • Now what if you want to read multiple function calls from a contract, in that case you can use the readContracts method.

      import { readContracts } from '@wagmi/core'
    
      const data = await readContracts({
        contracts: [
          {
            address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
            abi: mlootABI,
            functionName: 'getChest',
            args: [69],
          },
          {
            address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
            abi: mlootABI,
            functionName: 'getWaist',
            args: [69],
          },
        ],
      })
    
  • You can throw in a log when the connected address changes

      import { watchAccount } from '@wagmi/core'
    
      const unwatch = watchAccount((account) => console.log(account))
    
  • Finally what you've been waiting for, how to write to smart contract.

  •     import { writeContract } from '@wagmi/core'
    
        //use the prepareWriteContract
        const config = await prepareWriteContract({
          address: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
          abi: wagmigotchiABI,
          functionName: 'feed',
          args: [],
          overrides: {
            from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
            value: ethers.utils.parseEther('0.01'),
          },
        })
    
        const { hash } = await writeContract(config)
    
  • and finally what if you want to see the address of the account connected, in this case we can use the useAccount() hook

      import { useAccount, useConnect, useDisconnect } from 'wagmi'
      import { InjectedConnector } from 'wagmi/connectors/injected'
    
      function Profile() {
    
        const { address, isConnected } = useAccount()
    
        const { connect } = useConnect({
          connector: new InjectedConnector(),
        })
    
        const { disconnect } = useDisconnect()
    
        if (isConnected)
          return (
            <div>
              Connected to {address}
              <button onClick={() => disconnect()}>Disconnect</button>
            </div>
          )
        return <button onClick={() => connect()}>Connect Wallet</button>
    

Finally this is how you connect the client to the application.

import { WagmiConfig, createClient } from 'wagmi'
import { getDefaultProvider } from 'ethers'

const client = createClient({
  autoConnect: true,
  provider: getDefaultProvider(),
})

function App() {
  return (
    <WagmiConfig client={client}>
      <Profile />
    </WagmiConfig>

Project Time

Now that we've learnt all the basics let's build a small project.

  •   npm i @wagmi/core ethers
    
  • First of all, we need to set up the client. After that wrap the project in a <WagmiConfig client={client}><App/></WagmiConfig> , So now our entire application is wrapped in a wagmi config

  • Now let's go into our main component file and create a connect button. first of all we need the useConnect hooks to get all the functions necessary. from useConnect, we need the connectors and connect function

  • Now if we want to get the list of providers we can do the following

      {
      connectors.map(connector=>{
      <button key={connector.id} onClick={()=>connect({connector})}>{connector.name}
      </button>
      })
      }
    
  • Now we need to tell what happens when the user gets connected.

      const {isConnected} = useAccount(); //to check if the user is connected
      const router = useRouter();
    
      useEffect(()=>{
      if(isConnected) reouter.replace("/Dashboard");
      },[isConnected])
    

    if the dashboard is not created, go ahead and create a file under pages called dashboard.js that will display if it's connected.
    before we move forward you should review the above `useSendTransaction()` hook, which is used to send transactions. And Finally, look into use-debounce