The useReadContract
Hook
The useReadContract
hook is wagmi’s method of calling pure
and view
functions from your smart contracts. As with useAccount
, useReadContract
contains a number of helpful properties to enable you to manage displaying information to your users.
Objectives
By the end of this guide you should be able to:- Implement wagmi’s
useReadContract
hook to fetch data from a smart contract - Convert data fetched from a smart contract to information displayed to the user
- Identify the caveats of reading data from automatically-generated getters
Contract Setup
For this guide, you’ll be continuing from the project you started for theuseAccount
hook. You’ll work with an upgrade to the contract that you may have created if you completed the ERC 20 Tokens Exercise. See below for an example you can use if you don’t already have your own!
The contract creates a very simple DAO, in which users can create issues and vote for them, against them, or abstain. Anyone can claim
100 tokens. This is an insecure system for demonstration purposes, since it would be trivial to claim a large number of tokens with multiple wallets, then transfer them to a single address and use that to dominate voting.
But it makes it much easier to test!
If you’re using your own contract, please redeploy it with the following You also need to make the
view
functions:getIssue
function public
. The original spec called for it to be external
.Create Demo Issues
To start, you’ll need to put some data into your contract so that you can read it from your frontend. Open Sepolia BaseScan, find your contract, connect with your wallet, and call theclaim
function.
Add the following two issues:
getAllIssues
function under the Read Contract
tab to make sure all three are there.
Reading from your Smart Contract
To be able to read from your deployed smart contract, you’ll need two pieces of information: the address and ABI. These are used as parameters in theuseReadContract
hook.
If you’re using Hardhat, both of these can be conveniently found in a json file in the deployments/<network>
folder, named after your contract. For example, our contract is called FEWeightedVoting
, so the file is deployments/base-sepolia/FEWeightedVoting.json
.
If you’re using something else, it should produce a similar artifact, or separate artifacts with the ABI and address. If this is the case, make the adjustments you need when you import this data.
Either way, add a folder called deployments
and place a copy of the artifact file(s) inside.
Using the useReadContract
Hook
Add a file for a new component called IssueList.tsx
. You can start with:
interface
called Issue
that matches with the ReturnableIssue
type:
Be very careful here!
bigint
is the name of the type, BigInt
is the name of the constructor for that type. If you incorrectly use the constructor as the type, much of your code will still work, but other parts will express very confusing bugs.useState
and add a state variable to hold your list of Issue
s.
useReadContract
hook. It works similarly to the useAccount
hook. Configure it with:
useEffect
to do something when the call completes and the data. For now, just log it to the console:
index.tsx
:

- Renamed the properties decomposed from
useReadContract
to be specific for our function. Doing so is helpful if you’re going to read from more than one function in a file - Configured the hook with the address and ABI for your contract
- Made use of
useEffect
to wait for the data to be returned from the blockchain, log it to the console, and set the list ofIssue
s in state.
Displaying the Data
Now that you’ve got the data in state, you can display it via your component. One strategy to display a list of items is to compile aReactNode
array in a render function.
A Caveat with Automatic Getters
Remember how the Solidity compiler creates automatic getters for all of your public state variables? This feature is very helpful, but it can create bewildering results when you use it forstruct
s that contain mapping
s. Remember, nesting mappings cannot be returned outside the blockchain. The enumerableSet
protects you from this problem, because it has private variables inside it, which prevents setting issues
as public
. Had we instead used a mapping, we’d lose this protection:
useReadContract
to fetch an individual issue using the getter:
issueOne.desc
undefined? You can see it right there in the log!

voters
is missing from the data in the logs. What’s happening is that because the nested mapping
cannot be returned outside the blockchain, it simply isn’t. TypeScript then gets the data
and does the best it can to cast it as
an Issue
. Since voters
is missing, this will fail and it instead does the JavaScript trick of simply tacking on the extra properties onto the object.
Take a look at the working example above where you retrieved the list. Notice that the keys in your Issue
type are in that log, but are missing here. The assignment has failed, and all of the Issue
properties are null
.
Conclusion
In this guide, you’ve learned how to use theuseReadContract
hook to call pure
and view
functions from your smart contracts. You then converted this data into React state and displayed it to the user. Finally, you explored a tricky edge case in which the presence of a nested mapping
can cause a confusing bug when using the automatically-generated getter.
Simple DAO Contract Example
Use this contract if you don’t have your own from the ERC 20 Tokens Exercise. You can also use this if you want to cheat to get that badge. Doing so would be silly though!If you use your own contract, redeploy it with the
numberOfIssues
and getAllIssues
functions from the bottom of the contract below. We’ll need this for our first pass solution for getting all the Issues
in the contract.You also need to make the getIssue
function public
. The original spec called for it to be external
.