Improve Multicall Response Context #1699
Replies: 2 comments
-
Interesting idea! For the time-being, this works pretty well. import { erc20Abi } from 'abitype/abis'
import { createClient, http } from 'viem'
import { multicall } from 'viem/actions'
const client = createClient({ transport: http() })
const contracts = [
{
address: '0x...',
abi: erc20Abi,
functionName: 'balanceOf',
args: ['0x...'],
},
{
address: '0x...',
abi: erc20Abi,
functionName: 'balanceOf',
args: ['0x...'],
},
{
address: '0x...',
abi: erc20Abi,
functionName: 'balanceOf',
args: ['0x...'],
},
{
address: '0x...',
abi: erc20Abi,
functionName: 'balanceOf',
args: ['0x...'],
},
] as const
const results = await multicall(client, { contracts })
const merged = contracts.map(
(x, i) => ({ ...x, response: results[i] } as const),
)
merged[0].address
// ^? (property) address: '0x...'
merged[0].response.result
// ^? (property) result?: bigint | undefined |
Beta Was this translation helpful? Give feedback.
-
I agree with this, viem multicall is a blessing for us to optimize hitting multiple RPC call without getting a rate limit from public RPC. But at the same time managing multicall contexts is a challenge since currently we don't have an easy way to tie context for each result. Really hope there would be native viem feature for this ✋🏻. At the moment, I made a simple wrapper function Multicall Group that I used to create SDK on my team. It helps us a lot in managing multiple multicall contexts. Here's some example: const tokens: Address[] = [
// WETH
"0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
// ARB
"0x912ce59144191c1204e64559fe8253a0e49e6548",
// USDC
"0xaf88d065e77c8cc2239327c5edb3a432268e5831",
// USDC.e
"0xff970a61a04b1ca14834a43f5de4533ebddb5cc8",
];
const client = createPublicClient({
chain: arbitrum,
transport: http(),
});
const mg = new MulticallGroup(client);
const tokenInfos = tokens.map((address) => {
return {
tokenAddress: address,
resolver: mg.addContext({
contracts: [
{
address,
abi: erc20Abi,
functionName: "name",
},
{
address,
abi: erc20Abi,
functionName: "decimals",
},
{
address,
abi: erc20Abi,
functionName: "symbol",
},
],
formatter: (results) => ({
name: results[0] as string,
decimals: results[1] as bigint,
symbol: results[2] as string,
}),
}),
};
});
await mg.call();
const formattedTokenInfo = tokenInfos.map((info) => ({
tokenAddress: info.tokenAddress,
...info.resolver(),
})); We can also use this together with other context so e.g adding NFT call: // ...previous erc20 call
// before mg.call
const nftInfos = nfts.map((address) => {
return {
nftAddress: address,
resolver: mg.addContext({
contracts: [
{
address,
abi: erc721Abi,
functionName: "name",
},
{
address,
abi: erc721Abi,
functionName: "symbol",
},
],
formatter: (results) => ({
name: results[0] as string,
symbol: results[1] as string,
}),
}),
};
});
await mg.call()
// ...previous erc20 formatted info
// also format nft info unrelated to the erc20 info
const formattedNftInfo = nftInfos.map((info) => ({
nftAddress: info.nftAddress,
...info.resolver(),
})); P.S Sorry if I post it out of nowhere, just want to share how my team approaches this problem 🙏 |
Beta Was this translation helpful? Give feedback.
-
When using multicall to query data from several contracts, the returned results lack enough (any) context about the actual contract call itself which makes the handling of the return values more difficult. Consider an example where we want to query the
balanceOf
function for 25 different ERC0s. The returned result looks something like this:As you can see, there is no information as to which ERC20 contract corresponds to each result.
This is a fairly straightforward example, where array order can be used to match each result to its corresponding ERC20. However, this significantly limits more complex multicalls using several different functions on many different contracts as parsing the result of the multicall is nearly impossible.
I'd like to request an improved multicall return data type, which includes some context from the original call. Ideally, this would include (but not limited to) contract address, function name, and arguments passed in the config. This would allow for more complex multicalls and make the transition from an Ethers-based environment much easier.
Would this be an improvement the team would consider?
Beta Was this translation helpful? Give feedback.
All reactions