How to get the Ethereum and ERC-20 tokens balance of an address using Wagmi
In this tutorial, we are going to learn how to get the Ethereum balance and the ERC-20 tokens balance of an address in your React application using Wagmi or Ethers JS.
In this tutorial, we are going to learn how to get the Ethereum balance and the ERC-20 tokens balance of an address in your React application using Wagmi.
To do that, we use the useBalance
hook and in the parameters we pass the address we want to get the balance of.
If you want to get the balance of an ERC-20 token, you have to pass its address in the parameters as well. If you don't pass a token address, you'll get the Ethereum balance.
If you're not on the Ethereum network, your code will give you the balance of the native token of the blockchain you're on. For example, it will give you the BNB balance on the Binance Smart Chain, the FTM balance on Fantom, the MATIC balance on Polygon and so on...
If you pass a token address, you'll get the balance of that token on the blockchain your app is on.
Here is how to use that hook:
import { useState, useEffect } from 'react';
import { useBalance, useAccount } from 'wagmi';
import { utils } from 'ethers';
export const Home = () => {
// get the address of the connected wallet
const { address } = useAccount();
// get the Ethereum balance of the connected address
const { data: ethBalanceData, isError: ethBalanceError } = useBalance({
addressOrName: address,
});
// get the UNI balance of the connected address
const { data: uniBalanceData, isError: uniBalanceError } = useBalance({
addressOrName: address,
token: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
});
// if there is no wallet connected, ask to connect a wallet
if (!address) return <p>Please connect a wallet</p>;
// if there is an error, display it
if (ethBalanceError || uniBalanceError) return <p>Error while fetching balance</p>;
if (!ethBalanceData || !uniBalanceData) return <p>Loading balance...</p>;
return (
<>
<p>
You have {ethBalanceData.formatted} {ethBalanceData.symbol}
</p>
<p>
You have {uniBalanceData.formatted} {uniBalanceData.symbol}
</p>
</>
);
};
In the example above, we get the Ethereum balance and the balance of the Uniswap token of the connected wallet and display it.
The useBalance
hook takes in parameter an object that has the following properties (among others):
addresOrName
: the address or the ENS name of the wallet you want to get the balance oftoken
: the address of the smart contract of the token you want to get the balance of. If you don't pass anything, it will return the Ethereum balance
(or the native token of the blockchain you're on if you're not on Ethereum)formatUnits
: the units in which the balance is returned. It will be in Wei by default. Check out the documentation to see the units you can pass.watch
: iftrue
, the balance will be refreshed every new block and update thedata
returned. It isfalse
by default.
The rest of the properties you can pass can be found here:
In the example above, I pass in the address of the connected wallet which I get from the useAccount
hook. In the token
property, I pass nothing to get the Ethereum balance and the Uniswap token address to get the Uniswap token balance.
That hook will return an object containing the following properties:
data
: an object containing data about the balance.null
if there was an error while fetching the balance, if it's loading or before fetching the balance. The data object has this format:
•decimals
: the decimals of precision that the token balance has
•formatted
: a string containing the balance in Ether (instead of Wei)
•symbol
: the symbol of the token
•value
: the balance in wei (aBigNumber
)error
: an error object if the fetching the balance failed andnull
otherwiseisLoading
:true
while fetching the balance andfalse
otherwiseisError
:true
if there was an error fetching the balance andfalse
otherwiseisSuccess
:true
if the balance wasrefetch
: a function you can call to refetch the balance
Check out the documentation to see all the values that the hook returns.
The problem with this hook is that you can't get the balance of multiple tokens at once. You can use as many useBalance
hooks as you want but it's not very clean and scalable and it generates a log of repeated code.
Instead, we can use the useContractReads
hook which allows us to read data from multiple smart contracts (or call multiple read functions from the same smart contract).
In the parameters of that hook, we pass a contracts
property which is an array of objects with (at least) the following properties:
address
: the address of the smart contract to interact withabi
: an ABI for the smart contract containing at least the function you want to callfunctionName
: the name of the function to callargs
: an array containing the arguments to pass to the function you're calling
So in our case, the function we want to call is balanceOf
and the ABI should contain this function.
For the ABI, we can just use the ABI that Wagmi exports for ERC-20 tokens:
import { erc20ABI } from 'wagmi'
Here is an example in which I get the balance of 3 tokens of an address:
import { useContractReads } from 'wagmi'
import { erc20ABI } from 'wagmi'
import { utils } from 'ethers'
const addressToCheck = '0x5b8f1310A956ee1521A7bB56160451C786289aa9'
// We are going to re-use that for all the tokens we want to get the balance of
// because we call the same function for all of them, with the same arguments and the same ABI
const callBalanceOfConfig = {
abi: erc20ABI,
functionName: 'balanceOf',
// We need to pass the address to get the balance of in the parameters
args: [addressToCheck]
}
function GetMultipleBalances() {
const { data, error, isLoading } = useContractReads({
contracts: [
{
// The LINK token
address: '0x514910771AF9Ca656af840dff83E8264EcF986CA',
...callBalanceOfConfig
},
{
// The UNI token
address: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
...callBalanceOfConfig
},
{
// The AAVE token
address: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9',
...callBalanceOfConfig
}
],
})
if (error) return <p>Error while fetching balances</p>;
if (isLoading) return <p>Loading balances...</p>;
const tokensFetched = ['LINK', 'UNI', 'AAVE']
return (
<div>
{data && data.map((balance, i) => (
<p key={i}>
{/* make sure there is data before calling utils.formatEther */}
You have {balance ? utils.formatEther(balance) : '0'} {tokensFetched[i]}
</p>
))}
</div>
);
}
As you can see, the useContractReads
hook will return an object and we're going to use 3 properties from it:
data
: an array containing the results of our function calls. In our case it's the results of thebalanceOf
functions in the same order that we called them.error
: if there was an error while calling the functions, that property will contain the error that was thrown. Otherwise it'snull
.isLoading
: will betrue
while fetching the data andfalse
otherwise
So in this case, the balances will be in the data
array and we can simply map it to display the balances that we fetched.
The balances returned are not the objects like we had above with useBalance
, it's just the raw result of the balanceOf
function which is the balance in Wei
.
So we need to convert these balances from Wei
to Ether
using the formatEther
function from the utils in Ethers JS.
And that's it 🎉
Thank you for reading this article