A guide to redux-multicall: building a real-time dApp — Part B

Adekunle Michael Ajayi
7 min readDec 24, 2023

--

Photo by Toluwase S. Owononi

This is the second installment of a three-part series where we explore building real-time dApps using redux-multicall. If you’re looking for Part A, find it here. If you’re eager to dive into Part C (focused on actual usage), check it out here.

In this part, we’ll focus on setting up redux-multicall for use in your dApp. Let’s get started.

Project Starter Kit

To make this process smooth, a starter kit project has been set up. It’s a simple Next.js project with Tailwind CSS and Redux Toolkit. Before we begin, clone the repository here and follow the instructions in the README.md file to ensure we start on the same page.

Dependency Installation

To set up redux-multicall, install the necessary dependencies:

npm install @uniswap/redux-multicall @ethersproject/abi @ethersproject/bignumber @ethersproject/contracts @ethersproject/providers
  • @uniswap/redux-multicall: The redux-multicall library.
  • @ethersproject/abi, @ethersproject/bignumber, @ethersproject/contracts: Peer dependencies required by @uniswap/redux-multicall. the rest of the peer dependencies are already part of the starter kit.
  • @ethersproject/providers: The library used to instantiate a provider.

Env variables setup

Create a.env file to hold your RPC URL and CHAIN ID

NEXT_PUBLIC_CHAIN_ID=1
NEXT_PUBLIC_RPC_URL=<RPC_URL>

Replace <RPC_URL> with the RPC URL of your target chain. For this guide, we'll use Ethereum mainnet, hence the chain ID is set to 1.

Do not forget to add your .env to your .gitignore file to avoid pushing it to github.

Constants Setup

Next, inside src directory, create a directory named constants.

then inside the constants directory you just created, create a index.ts file and paste the following in it

const env_CHAIN_ID = process.env.NEXT_PUBLIC_CHAIN_ID;
const env_RPC_URL = process.env.NEXT_PUBLIC_RPC_URL;

export const CHAIN_ID = env_CHAIN_ID ? (env_CHAIN_ID as unknown as number) : 1;
export const RPC_URL = env_RPC_URL ?? "https://eth.llamarpc.com";

This file exports CHAIN_ID and RPC_URL with fallback values for cases where the .env file is not provided.

Provider Setup

Create a provider.ts file inside the src/constants directory, and paste the following code in it:

import { JsonRpcProvider } from "@ethersproject/providers";
import { RPC_URL } from ".";

export const provider = new JsonRpcProvider(RPC_URL);

useLatestBlock hook

Another thing we need to have in place before we start configuring redux-multicall is a way to get latest block as they are added to the chain.

Redux multicall needs to have the knowledge of new blocks as they’re formed on the blockchain network where it is fetching data. You can implement this however you like. For this guide, a simple hook will suffice. It will give us the latest block number everytime we have one. Redux multicall revalidates the data when it receives a new block number based on the specified configuration.

To create our useLatestBlock hook

Inside the src, directory create a directory named hooks. And inside the hooks directory, create a file named useLatestBlock.ts and paste the following code in it

import { JsonRpcProvider } from "@ethersproject/providers";
import { useEffect, useState } from "react";

export function useLatestBlock(provider: JsonRpcProvider) {
const [blockNumber, setBlockNumber] = useState<number | undefined>(
undefined
);
useEffect(() => {
if (!provider) return;
const onBlock = (num: number) => setBlockNumber(num);
provider.on("block", onBlock);
return () => {
provider.off("block", onBlock);
};
}, [provider, setBlockNumber]);
return blockNumber;
}

This hook listens for the ‘block’ event on the provider, providing the latest block number each time the event occurs.

For a more sophisticated implemetation, take a look at this github gist. it is well suited for multichain dApp where the user has the ability of switching chains. It uses react context instead. This is what uniswap interface uses at the time of writting this. but for our usecase in this example, we’re good with a simple useLatestBlock hook

UniswapInterfaceMulticall

The uniswap team made some modification to the markerdao multicall2 contract for use in redux-multcall and nameit UniswapInterfaceMulticall. you can find it here

The uniswap team already have this constract deployed on various chains.

0x1F98415757620B543A52E61c46B32eB19261F984 — on ethereum mainnet, optimism, optimism goerli, polygon, and polygon mumbai

0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB — on arbitrum one

0xa501c031958F579dB7676fF1CE78AD305794d579 — on arbitrum rinkeby

0x633987602DE5C4F337e3DbF265303A1080324204 — on celo and celo alfajores.

If you’re building on a different chain but can’t find it for your target network, a simple search may help. If you still can’t find it after seaching, simply take the source code and deploy on your intended chain.

In this guide, we will be building on etherum mainnet. So inside src/constants/index.ts file, add this line

export const uniswapInterfaceMulticallAddress = "0x1F98415757620B543A52E61c46B32eB19261F984";

The src/constants/index.ts file should now be something like this

UniswapInterfaceMulticall ABI

Of course, to create a contract instance, you need the ABI of the said contract. You can copy the abi from the contract tab of one of the address above. (ethereum network)

Inside the src directory, create a directory named abis, inside it, create a json file named uniswapInterfaceMulticall.json and paste in the ABI.

Redux-Multicall Setup

Now, We are finally ready to begin redux-multicall setup.

I like to separate my redux-multicall setup code. So, inside the src directory, create a directory named multicall, Inside it, create an index.tsx file and paste in the following code.

import { createMulticall } from "@uniswap/redux-multicall";

const multicall = createMulticall({ reducerPath: "multicall" });

export default multicall;

In this file, we created an instance of redux-multicall using createMulticall and passed in reducerPath. the reducerPath you passed is the name that will be given to the redux-multicall state in your redux store. You can as well leave it empy and not pass in any object as argument and reducerPathwill default to “multicall”

Now, the multicall variable we got from calling createMulticall is an object that contains actions, reducerPath, reducer, hooks, and updater. If you don’t know what any of these are, I recommend going back to read part A

Updater Component

To create the Updater Component that will be rendered at the root of our application, inside the multicall directory, create a file named updater.tsx and paste in the following code

import type { ListenerOptions } from "@uniswap/redux-multicall";
import multicallABI from "../abis/uniswapInterfaceMulticall.json";
import { provider } from "../constants/provider";
import { useLatestBlock } from "../hooks/useLatestBlock";
import { Contract } from "@ethersproject/contracts";
import multicall from ".";
import { uniswapInterfaceMulticallAddress } from "@/constants";

const MulticallUpdater = () => {
const blockNumber = useLatestBlock(provider);

const listenerOptions: ListenerOptions = {
blocksPerFetch: 1,
};

const uniswapMulticall = new Contract(
uniswapInterfaceMulticallAddress,
multicallABI,
provider
);

return (
<multicall.Updater
chainId={1}
latestBlockNumber={blockNumber}
contract={uniswapMulticall}
listenerOptions={listenerOptions}
/>
);
};

export default MulticallUpdater;

The MulticallUpdater in this file Basically renders the Updater from the multicall object in the last step, passing in necessary props. If you have problems understanding any of the props, or why we are passing them, again, I recommend going back to read Part A

Next, render <MulticallUpdater /> in the root of your app like so

Redux-multicall’s reducer

Next, let’s bring our redux-multicall reducer in to our redux store

If you look inside the redux store in src/state/index.ts, you’ll see that our reducers object is still empy. all we have to do is import our multicall from src/multicall/index.tsx, and add this line to the currently empty reducer object

[multicall.reducerPath]: multicall.reducer

The file should now look like this:

Save the file and start your app if it’s not already started. Check your browser’s console to be sure nothing is broken.

if you have redux devtool installed in your brower go to it and it should look something like this

expanding the muticall state will look like this

you can see that the listenerOption is as we have specified in our setup. also, the callResult is still empty because we have not started making calls. As we begin to make calls, we will have a new object named callListeners. this is where reduxt-multicall keeps track of all our calls, and the updater uses it to know which calls it needs to make when it’s time to revalidate our data.

Conclusion

In this article, we took a step-by-step process setting up redux-multicall for use in our dApp. In The next part which is Part C, we will go over how to use it in our application.

You can find the repository of the setup here.

Questions or Clarifications? Connect on X!

If you have any questions, need clarifications, or just want to discuss, feel free to reach out to me on X at https://x.com/0xAdek. I look forward to assist and engage in conversations related to the guide.

Happy coding!

--

--

Adekunle Michael Ajayi
Adekunle Michael Ajayi

No responses yet