import { Interface, Result } from "@ethersproject/abi"; import Web3 from "web3"; import { getMulticallContract } from "../constants/contracts"; export interface MultiCallPayload { targetInterface: Interface; target: string; method: string; transformResult?: (res: Result) => any; data?: any[]; } export async function multicallMultipleContractSingleData( web3: Web3, targetInterface: Interface, targets: string[], method: string, data?: any[], block?: number ) { const multicallContract = getMulticallContract(web3); if (!multicallContract) { return []; } const fragment = targetInterface.getFunction(method); const calls: [string, string][] = targets.map((target) => [ target, targetInterface.encodeFunctionData(fragment, data), ]); const { returnData }: { returnData: string[] } = await multicallContract.methods.aggregate(calls).call({}, block); return returnData.map((el) => targetInterface.decodeFunctionResult(fragment, el) ); } export async function multicallSingleContractMultipleData( web3: Web3, targetInterface: Interface, target: string, method: string, data: any[][] ) { const multicallContract = getMulticallContract(web3); const fragment = targetInterface.getFunction(method); const calls: [string, string | number[]][] = data.map((el) => [ target, targetInterface.encodeFunctionData(fragment, el), ]); const { returnData }: { returnData: string[] } = await multicallContract.methods.aggregate(calls).call(); return returnData.map((el) => targetInterface.decodeFunctionResult(fragment, el) ); } export async function multicallMultipleContractMultipleData( web3: Web3, payload: MultiCallPayload[] ) { const multicallContract = getMulticallContract(web3); const calls: [string, string | number[]][] = payload.map( ({ targetInterface, target, method, data }) => { const fragment = targetInterface.getFunction(method); const call = [target, targetInterface.encodeFunctionData(fragment, data)]; return call as [string, string | number[]]; } ); const { returnData }: { returnData: string[] } = await multicallContract.methods.aggregate(calls).call(); return returnData.map((res, i) => { const { targetInterface, method, transformResult } = payload[i]; const fragment = targetInterface.getFunction(method); const decodedResult = targetInterface.decodeFunctionData(fragment, res); return transformResult ? transformResult(decodedResult) : decodedResult; }); }