import { ref, markRaw } from 'vue' import { Contract, ContractInterface } from '@ethersproject/contracts' import { MULTICALL2_ABI, MULTICALL2_ADDRESS } from '../constants' import { Multicall2 } from '../types/multicall2/Multicall2' import { Web3Provider, JsonRpcProvider } from '@ethersproject/providers' import { Result, Interface } from '@ethersproject/abi' export type ContractCall = { interface: ContractInterface address: string method: string args?: any[] } export function useMulticall(provider: Web3Provider | JsonRpcProvider) { const results = ref([]) const blockNumber = ref(0) const multicall = markRaw( new Contract(MULTICALL2_ADDRESS, MULTICALL2_ABI, provider) as Multicall2, ) interface Call { target: string callData: string } async function call(contractCalls: ContractCall[]) { const calls: Call[] = contractCalls.map((call) => { const iface = getInterface(call.interface) return { target: call.address, callData: iface.encodeFunctionData(call.method, call.args), } }) const { blockNumber: blocNum, returnData } = await tryBlockAndAggregate( calls, ) results.value = returnData.map((data, i) => { if (!data.success) console.error(`Failed to call ${contractCalls[i].method}`) const iface = getInterface(contractCalls[i].interface) return iface.decodeFunctionResult( contractCalls[i].method, data.returnData, ) }) blockNumber.value = blocNum.toNumber() } async function tryBlockAndAggregate(calls: Call[]) { return await multicall.callStatic.tryBlockAndAggregate(false, calls) } return { multicall, blockNumber, results, call, } } function getInterface(contractInterface: ContractInterface): Interface { if (Interface.isInterface(contractInterface)) { return contractInterface } return new Interface(contractInterface) }