Founder of threedots.io I build, write and love.
Founder of threedots.io I build, write and love.

Subscribe to MarcoSolis.eth

Subscribe to MarcoSolis.eth
Share Dialog
Share Dialog

This is the first article in a series on how we are integrating different technologies to create the Otomee NFT Marketplace and how you can do it too.
The Multicall implementation uses redux, so you will need to have it set-up on your application.
Dependancies
ethers
@typechain/ethers-v5
@uniswap/redux-multicall
@uniswap/v3-periphery
.
├── state
│ ├── index.ts
│ └── multicall
│ ├── instance.ts
│ └── hooks.ts
│ └── updater.ts
├── hooks
│ ├── useContract.ts
├── const
│ ├── addresses.ts
├── abis
└── index.tsx
Now that we have everything we need, let’s get into it!
This will be very simple. Here we just create a multicall instance with default settings*:*
import { createMulticall } from '@uniswap/redux-multicall'
export const multicall = createMulticall()
Now we define the hooks which will be used to make the contract calls:
import { useActiveWeb3React } from '../../hooks/web3'
import { SkipFirst } from '../../types/tuple'
import { useBlockNumber } from '../application/hooks'
import { multicall } from './instance'
export type { CallStateResult } from '@uniswap/redux-multicall'
export { NEVER_RELOAD } from '@uniswap/redux-multicall'const {
useMultipleContractSingleData: _useMultipleContractSingleData,
useSingleCallResult: _useSingleCallResult,
useSingleContractMultipleData: _useSingleContractMultipleData,
} = multicall.hookstype SkipFirstTwoParams<T extends (...args: any) => any> = SkipFirst<Parameters<T>, 2>export function useMultipleContractSingleData(...args: SkipFirstTwoParams<typeof _useMultipleContractSingleData>) {
const { chainId, latestBlock } = useCallContext()
return _useMultipleContractSingleData(chainId, latestBlock, ...args)
}export function useSingleCallResult(...args: SkipFirstTwoParams<typeof _useSingleCallResult>) {
const { chainId, latestBlock } = useCallContext()
return _useSingleCallResult(chainId, latestBlock, ...args)
}export function useSingleContractMultipleData(...args: SkipFirstTwoParams<typeof _useSingleContractMultipleData>) {
const { chainId, latestBlock } = useCallContext()
return _useSingleContractMultipleData(chainId, latestBlock, ...args)
}function useCallContext() {
const { chainId } = useActiveWeb3React()
const latestBlock = useBlockNumber()
return { chainId, latestBlock }
}
Now let’s break it down:
useActiveWeb3React is a hook created to provide us with thee Web3 context, it is used to get the chainID and Latest block needed on the contract calls. The recently created multicall instance is imported too. CallStateResult and NEVER_RELOAD are just imported for convenience.
Then we define the multicall hooks and proceed to wrap them adding the chainID and latestBlock parameters so the reducers don’t have to.
A quick overview of the hooks:
useSingleCallResult: This is the simplest one, you can use it to make a call to a single SC, for example, here we use the Multicall contract to call the *getCurrentBlockTimestamp *method of itself, but you can change the *multicallContract *argument to any SC.
const result = useSingleCallResult(
multicallContract,
'getCurrentBlockTimestamp')?.result?.[0]
This is the method we will use to call the ENS resolver and registrar contracts.
useSingleContractMultipleData: You can use this hook to make call the same method of the same Smart Contract several times with different parameters. We use it to get the Eth balance of several addresses stored on a map, using the Multicall contract method getEthBalance:
const results = useSingleContractMultipleData(
multicallContract,
'getEthBalance',
addresses.map((address) => [address]))
useMultipleContractSingleData: You can use this to make the same call to several Smart contracts with a the same interface. For example, if you would like to get the reserves of multiple Uniswap Pool contracts, you can call it like this:
const results = useMultipleContractSingleData(pairAddresses, PAIR_INTERFACE, 'getReserves')
Before diving into *updater.js *we need to create the hook to actually use a contract, as we will need to pass it to the multicall updater.
import { Contract } from '@ethersproject/contracts'
import { abi as MulticallABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
import { useMemo } from 'react'
import { MULTICALL_ADDRESS } from 'constants/addresses'
import { useActiveWeb3React } from './web3'function getContract(address: string, ABI: any, library: Web3Provider, account?: string): Contract {
if (!isAddress(address) || address === AddressZero) {
throw Error(`Invalid 'address' parameter '${address}'.`)
}
return new Contract(address, ABI, getProviderOrSigner(library, account) as any)
}export function useContract<T extends Contract = Contract>(addressOrAddressMap: string | { [chainId: number]: string } | undefined,
ABI: any,
withSignerIfPossible = true): T | null {
const { library, account, chainId } = useActiveWeb3React()
return useMemo(() => {
if (!addressOrAddressMap || !ABI || !library || !chainId) return null
let address: string | undefined
if (typeof addressOrAddressMap === 'string') address = addressOrAddressMap
else address = addressOrAddressMap[chainId]
if (!address) return null
try {
return getContract(address, ABI, library, withSignerIfPossible && account ? account : undefined)
} catch (error) {
console.error('Failed to get contract', error)
return null
}
}, [addressOrAddressMap, ABI, library, chainId, withSignerIfPossible, account]) as T
}export function useMulticall2Contract() {
return useContract<UniswapInterfaceMulticall>(MULTICALL_ADDRESS, MulticallABI, false) as UniswapInterfaceMulticall
}
*useContract *checks the inputs before returning a Contract object from the *ethersproject *library using the getContract function. Then, we proceed to wrap it to create a kook to use the Multicall contract.
Don’t forget to export *MULTICALL_ADDRESS *in constants/addresses.ts!
Here you can create the wrappers to use any SC you’d like to use. The ENS SCs wrappers will be implemented later.
Now we are ready to create Updater wrappers that pull needed info from store, using the *useMulticall2Contract *function we just created:
import { useMulticall2Contract } from 'hooks/useContract'
import { useActiveWeb3React } from 'hooks/web3'
import { useBlockNumber } from 'state/application/hooks'
import { multicall } from './instance'export default function Updater() {
const latestBlockNumber = useBlockNumber()
const { chainId } = useActiveWeb3React()
const multicall2Contract = useMulticall2Contract()
return <multicall.Updater chainId={chainId} latestBlockNumber={latestBlockNumber} contract={multicall2Contract} />
}
Import the multicall instance and add the reducer to your root redux reducer.
import { multicall } from './multicall/instance'export const rootReducer = combineReducers({
// Other reducers
multicall: multicall.reducer
})
Finally, add the updated inside your web3 and redux wrappers in your root index.tsx:
import MulticallUpdater from 'state/multicall/updater'ReactDOM.render(
<StrictMode>
<Provider store={store}>
<Web3ReactProvider>
<MulticallUpdater/>
<ThemeProvider>
<ThemedGlobalStyle />
<App />
</ThemeProvider>
</Web3ReactProvider>
</Provider>
</StrictMode>,
document.getElementById('root'));
If you have any questions, don’t hesitate to contact me!
web: Threedots.io
mail: marco@threedots.io
Twitter: @itsMarcoSolis

This is the first article in a series on how we are integrating different technologies to create the Otomee NFT Marketplace and how you can do it too.
The Multicall implementation uses redux, so you will need to have it set-up on your application.
Dependancies
ethers
@typechain/ethers-v5
@uniswap/redux-multicall
@uniswap/v3-periphery
.
├── state
│ ├── index.ts
│ └── multicall
│ ├── instance.ts
│ └── hooks.ts
│ └── updater.ts
├── hooks
│ ├── useContract.ts
├── const
│ ├── addresses.ts
├── abis
└── index.tsx
Now that we have everything we need, let’s get into it!
This will be very simple. Here we just create a multicall instance with default settings*:*
import { createMulticall } from '@uniswap/redux-multicall'
export const multicall = createMulticall()
Now we define the hooks which will be used to make the contract calls:
import { useActiveWeb3React } from '../../hooks/web3'
import { SkipFirst } from '../../types/tuple'
import { useBlockNumber } from '../application/hooks'
import { multicall } from './instance'
export type { CallStateResult } from '@uniswap/redux-multicall'
export { NEVER_RELOAD } from '@uniswap/redux-multicall'const {
useMultipleContractSingleData: _useMultipleContractSingleData,
useSingleCallResult: _useSingleCallResult,
useSingleContractMultipleData: _useSingleContractMultipleData,
} = multicall.hookstype SkipFirstTwoParams<T extends (...args: any) => any> = SkipFirst<Parameters<T>, 2>export function useMultipleContractSingleData(...args: SkipFirstTwoParams<typeof _useMultipleContractSingleData>) {
const { chainId, latestBlock } = useCallContext()
return _useMultipleContractSingleData(chainId, latestBlock, ...args)
}export function useSingleCallResult(...args: SkipFirstTwoParams<typeof _useSingleCallResult>) {
const { chainId, latestBlock } = useCallContext()
return _useSingleCallResult(chainId, latestBlock, ...args)
}export function useSingleContractMultipleData(...args: SkipFirstTwoParams<typeof _useSingleContractMultipleData>) {
const { chainId, latestBlock } = useCallContext()
return _useSingleContractMultipleData(chainId, latestBlock, ...args)
}function useCallContext() {
const { chainId } = useActiveWeb3React()
const latestBlock = useBlockNumber()
return { chainId, latestBlock }
}
Now let’s break it down:
useActiveWeb3React is a hook created to provide us with thee Web3 context, it is used to get the chainID and Latest block needed on the contract calls. The recently created multicall instance is imported too. CallStateResult and NEVER_RELOAD are just imported for convenience.
Then we define the multicall hooks and proceed to wrap them adding the chainID and latestBlock parameters so the reducers don’t have to.
A quick overview of the hooks:
useSingleCallResult: This is the simplest one, you can use it to make a call to a single SC, for example, here we use the Multicall contract to call the *getCurrentBlockTimestamp *method of itself, but you can change the *multicallContract *argument to any SC.
const result = useSingleCallResult(
multicallContract,
'getCurrentBlockTimestamp')?.result?.[0]
This is the method we will use to call the ENS resolver and registrar contracts.
useSingleContractMultipleData: You can use this hook to make call the same method of the same Smart Contract several times with different parameters. We use it to get the Eth balance of several addresses stored on a map, using the Multicall contract method getEthBalance:
const results = useSingleContractMultipleData(
multicallContract,
'getEthBalance',
addresses.map((address) => [address]))
useMultipleContractSingleData: You can use this to make the same call to several Smart contracts with a the same interface. For example, if you would like to get the reserves of multiple Uniswap Pool contracts, you can call it like this:
const results = useMultipleContractSingleData(pairAddresses, PAIR_INTERFACE, 'getReserves')
Before diving into *updater.js *we need to create the hook to actually use a contract, as we will need to pass it to the multicall updater.
import { Contract } from '@ethersproject/contracts'
import { abi as MulticallABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
import { useMemo } from 'react'
import { MULTICALL_ADDRESS } from 'constants/addresses'
import { useActiveWeb3React } from './web3'function getContract(address: string, ABI: any, library: Web3Provider, account?: string): Contract {
if (!isAddress(address) || address === AddressZero) {
throw Error(`Invalid 'address' parameter '${address}'.`)
}
return new Contract(address, ABI, getProviderOrSigner(library, account) as any)
}export function useContract<T extends Contract = Contract>(addressOrAddressMap: string | { [chainId: number]: string } | undefined,
ABI: any,
withSignerIfPossible = true): T | null {
const { library, account, chainId } = useActiveWeb3React()
return useMemo(() => {
if (!addressOrAddressMap || !ABI || !library || !chainId) return null
let address: string | undefined
if (typeof addressOrAddressMap === 'string') address = addressOrAddressMap
else address = addressOrAddressMap[chainId]
if (!address) return null
try {
return getContract(address, ABI, library, withSignerIfPossible && account ? account : undefined)
} catch (error) {
console.error('Failed to get contract', error)
return null
}
}, [addressOrAddressMap, ABI, library, chainId, withSignerIfPossible, account]) as T
}export function useMulticall2Contract() {
return useContract<UniswapInterfaceMulticall>(MULTICALL_ADDRESS, MulticallABI, false) as UniswapInterfaceMulticall
}
*useContract *checks the inputs before returning a Contract object from the *ethersproject *library using the getContract function. Then, we proceed to wrap it to create a kook to use the Multicall contract.
Don’t forget to export *MULTICALL_ADDRESS *in constants/addresses.ts!
Here you can create the wrappers to use any SC you’d like to use. The ENS SCs wrappers will be implemented later.
Now we are ready to create Updater wrappers that pull needed info from store, using the *useMulticall2Contract *function we just created:
import { useMulticall2Contract } from 'hooks/useContract'
import { useActiveWeb3React } from 'hooks/web3'
import { useBlockNumber } from 'state/application/hooks'
import { multicall } from './instance'export default function Updater() {
const latestBlockNumber = useBlockNumber()
const { chainId } = useActiveWeb3React()
const multicall2Contract = useMulticall2Contract()
return <multicall.Updater chainId={chainId} latestBlockNumber={latestBlockNumber} contract={multicall2Contract} />
}
Import the multicall instance and add the reducer to your root redux reducer.
import { multicall } from './multicall/instance'export const rootReducer = combineReducers({
// Other reducers
multicall: multicall.reducer
})
Finally, add the updated inside your web3 and redux wrappers in your root index.tsx:
import MulticallUpdater from 'state/multicall/updater'ReactDOM.render(
<StrictMode>
<Provider store={store}>
<Web3ReactProvider>
<MulticallUpdater/>
<ThemeProvider>
<ThemedGlobalStyle />
<App />
</ThemeProvider>
</Web3ReactProvider>
</Provider>
</StrictMode>,
document.getElementById('root'));
If you have any questions, don’t hesitate to contact me!
web: Threedots.io
mail: marco@threedots.io
Twitter: @itsMarcoSolis
<100 subscribers
<100 subscribers
No activity yet