Git Product home page Git Product logo

ethereum-multicall's Issues

Execution failed

const ethereumMulticall = require("ethereum-multicall");
const { ethers } = require("ethers");

//   let provider = ethers.getDefaultProvider();

async function go() {
  // you can use any ethers provider context here this example is
  // just shows passing in a default provider, ethers hold providers in
  // other context like wallet, signer etc all can be passed in as well.
  const multicall = new ethereumMulticall.Multicall({
    nodeUrl: "https://bsc-pokt.nodies.app",
    tryAggregate: true,
  });

  const contractCallContext = [
    {
      reference: "testContract2",
      contractAddress: "0x55d398326f99059fF775485246999027B3197955",
      abi: [
        {
          name: "totalSupply",
          type: "function",
          inputs: [],
          outputs: [{ name: "", type: "uint256" }],
        },
      ],
      calls: [
        {
          reference: "fooTwoCall",
          methodName: "totalSupply",
          methodParameters: [],
        },
      ],
    },
  ];

  const results = await multicall.call(contractCallContext);
  console.log(results);
}

go();

Fail msg

/Users/js/node_modules/@ethersproject/logger/lib/index.js:238
        var error = new Error(message);
                    ^

Error: unable to determine stateMutability (argument="value", value={"name":"totalSupply","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256"}]}, code=INVALID_ARGUMENT, version=abi/5.7.0)
    at Logger.makeError (/Users/js/node_modules/@ethersproject/logger/lib/index.js:238:21)
    at Logger.throwError (/Users/ll/code/js/node_modules/@ethersproject/logger/lib/index.js:247:20)
    at Logger.throwArgumentError (/Users/ll/code/js/node_modules/@ethersproject/logger/lib/index.js:250:21)
    at verifyState (/Users/ll/code/js/node_modules/@ethersproject/abi/lib/fragments.js:588:16)
    at FunctionFragment.fromObject (/Users/ll/code/js/node_modules/@ethersproject/abi/lib/fragments.js:728:21)
    at Fragment.fromObject (/Users/ll/code/js/node_modules/@ethersproject/abi/lib/fragments.js:371:41)
    at Fragment.from (/Users/ll/code/js/node_modules/@ethersproject/abi/lib/fragments.js:363:25)
    at /Users/ll/code/js/node_modules/@ethersproject/abi/lib/interface.js:101:41
    at Array.map (<anonymous>)
    at new Interface (/Users/ll/code/js/node_modules/@ethersproject/abi/lib/interface.js:100:65) {
  reason: 'unable to determine stateMutability',
  code: 'INVALID_ARGUMENT',
  argument: 'value',
  value: {
    name: 'totalSupply',
    type: 'function',
    inputs: [],
    outputs: [ { name: '', type: 'uint256' } ]
  }
}

Node.js v18.17.1

"ethereum-multicall": "^2.21.0",
"ethers": "^5.7.0",

What's the matter with the code?

Add python usage examples

Nice work! Thanks for sharing with everyone. Any chance you could add python usage examples to the list of languages on the main page? Please consider that for the py family. Thanks again.

Fantom

It seems like Fantom blockchain is not supported.

Im getting

Returned error: the method net_version does not exist/is not available

Tron Mainnet

Can this library be used for the Tron mainnet?

'Cannot read properties of undefined' while call

I have parts of code:

this.multicall = new ethereumMulticall .Multicall({ nodeUrl: config.rpc, tryAggregate: true });
or
this.multicall = new ethereumMulticall .Multicall({ ethersProvider: connect.provider, tryAggregate: true });

and

let answ = await this.multicall.call({});
or
answ = await this.multicall.call(multicallContext);

All combinations (with empty context too) executing gives same error:
`
/node_modules/ethereum-multicall/node_modules/@ethersproject/abi/lib/interface.js:101
properties_1.defineReadOnly(this, "fragments", abi.map(function (fragment) {
^

TypeError: Cannot read properties of undefined (reading 'map')

`

Passing an array in CallContext entry

Hi I am receiving this error when trying to call getAmountsOut on uniswap router

Error: call revert exception; VM Exception while processing transaction: reverted with reason string "Multicall aggregate: call failed" [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="aggregate((address,bytes)[])", data="0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000204d756c746963616c6c206167677265676174653a2063616c6c206661696c6564", errorArgs=["Multicall aggregate: call failed"], errorName="Error", errorSignature="Error(string)", reason="Multicall aggregate: call failed", code=CALL_EXCEPTION, version=abi/5.6.3) at Logger.makeError (/Users/johnathonlam/Documents/work/data-collection/node_modules/@ethersproject/logger/src.ts/index.ts:261:28) at Logger.throwError (/Users/johnathonlam/Documents/work/data-collection/node_modules/@ethersproject/logger/src.ts/index.ts:273:20) at Interface.decodeFunctionResult (/Users/johnathonlam/Documents/work/data-collection/node_modules/@ethersproject/abi/src.ts/interface.ts:427:23) at Object.<anonymous> (/Users/johnathonlam/Documents/work/data-collection/node_modules/@ethersproject/contracts/src.ts/index.ts:400:44) at step (/Users/johnathonlam/Documents/work/data-collection/node_modules/@ethersproject/contracts/lib/index.js:48:23) at Object.next (/Users/johnathonlam/Documents/work/data-collection/node_modules/@ethersproject/contracts/lib/index.js:29:53) at fulfilled (/Users/johnathonlam/Documents/work/data-collection/node_modules/@ethersproject/contracts/lib/index.js:20:58) at processTicksAndRejections (node:internal/process/task_queues:96:5) { reason: 'Multicall aggregate: call failed', code: 'CALL_EXCEPTION', method: 'aggregate((address,bytes)[])', data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000204d756c746963616c6c206167677265676174653a2063616c6c206661696c6564', errorArgs: [ 'Multicall aggregate: call failed' ], errorName: 'Error', errorSignature: 'Error(string)', address: '0xC50F4c1E81c873B2204D7eFf7069Ffec6Fbe136D', args: [ [ [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object] ] ],

The way I am trying to pass in the data is like

{ reference: info.address + '_' + info.token1, contractAddress: chainConfig.bsc.dex.pancakeswap.router, abi: uniswapRouterAbi, calls: [ { reference: 'amount', methodName: 'getAmountsOut', methodParameters: [info.token1reserve, [info.token1, chainConfig.bsc.dex.pancakeswap.nativeCurrency]] }, ], }

Map reference as contract address

Hello. Is it possible to map a reference from 1 contract call to be passed as a value to another contract call?

So I would like to get a PAIR of a token-BnB and then use that pair address to call getReserves

[
    {
      reference: 'factory',
      contractAddress: factoryAddress,
      abi: factoryABI,
      calls: [
        { reference: 'tokenPair', methodName: 'getPair', methodParameters: [tokenAddress, bnbAddress] },
      ]
    },
    {
      reference: 'liquidity',
      contractAddress: tokenPair,   <-----------------------------------------------------------
      abi: [
        {
          'constant': true,
          'inputs': [],
          'name': 'getReserves',
          'outputs': [
            { 'internalType': 'uint112', 'name': '_reserve0', 'type': 'uint112' },
            { 'internalType': 'uint112', 'name': '_reserve1', 'type': 'uint112' },
            { 'internalType': 'uint32', 'name': '_blockTimestampLast', 'type': 'uint32' }
          ],
          'payable': false,
          'stateMutability': 'view',
          'type': 'function'
        }
      ],
      calls: [
        { methodName: 'getReserves' },
      ]
    }
  ]

multicall.call result success is true but no tx is sent to blockchain

Hi there, I´m playing around with multicalls at my hardhat local environment.

I deployed this Multicall3 https://etherscan.io/address/0xcA11bde05977b3631167028862bE2a173976CA11#code
the only change I did was moving from version 0.8.12 to 0.8.17

This is my multicall object creation:

const multicall = new ethereumMulticall.Multicall({ 
            ethersProvider:hre.ethers.provider, 
            tryAggregate: true, 
            multicallCustomContractAddress: _multiCall3.address  //the address of the deployed multicall
});

The provider should be OK. I tried with hre.ethers.getDefaultProvider(), but the blockNumber I was getting in the response made me realise it was not correct. I also checked this against goerli and with hre.ethers.provider I´m getting the correct block number.

After the multicall.call, the state of my contract is not being changed and it should.
I thought it could be something wrong in my contract implementation but I tried to replicate this using goerli. I noticed that no transaction is being sent to the blockchain after the multicall.call is done and I got success:true.

Multicallv3
https://goerli.etherscan.io/address/0xc1862322861093b5b6944c305963ea2e9ffe5519
ERC20PermitToken
https://goerli.etherscan.io/address/0x871663104598d79d41d89461cc4f18f71b01db3b

MultiCall.call

await multicall.call(contractCallContext);

ContractCallContext:

[
   {
      "reference":"ERC20PermitToken",
      "contractAddress":"0x871663104598d79D41d89461CC4F18f71b01db3b",
      "abi":[
         {
            "inputs":[
               {
                  "internalType":"address",
                  "name":"owner",
                  "type":"address"
               },
               {
                  "internalType":"address",
                  "name":"spender",
                  "type":"address"
               },
               {
                  "internalType":"uint256",
                  "name":"value",
                  "type":"uint256"
               },
               {
                  "internalType":"uint256",
                  "name":"deadline",
                  "type":"uint256"
               },
               {
                  "internalType":"uint8",
                  "name":"v",
                  "type":"uint8"
               },
               {
                  "internalType":"bytes32",
                  "name":"r",
                  "type":"bytes32"
               },
               {
                  "internalType":"bytes32",
                  "name":"s",
                  "type":"bytes32"
               }
            ],
            "name":"permit",
            "outputs":[
               
            ],
            "stateMutability":"nonpayable",
            "type":"function"
         }
      ],
      "calls":[
         {
            "reference":"permit",
            "methodName":"permit",
            "methodParameters":[
               "0x0C7ebAC9957C01F0b891B912895A811338aF4Ae0",
               "0x02af0F2eE01523357B11cBb1B86BA66eb8D2bfED",
               {
                  "type":"BigNumber",
                  "hex":"0x01"
               },
               {
                  "type":"BigNumber",
                  "hex":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
               },
               28,
               "0xef92a36fc7c2fa26ee4275d73918f03ae651708377026c4e936c76f39f9327ca",
               "0x0b2d9ef10de8200043ffccd2be22e68ef94efe96a1411dbff3aa57b913957da0"
            ]
         }
      ]
   }
]

Result: goerli execution

{
   "results":{
      "ERC20PermitToken":{
         "originalContractCallContext":{
            "reference":"ERC20PermitToken",
            "contractAddress":"0x871663104598d79D41d89461CC4F18f71b01db3b",
            "abi":[
               {
                  "inputs":[
                     {
                        "internalType":"address",
                        "name":"owner",
                        "type":"address"
                     },
                     {
                        "internalType":"address",
                        "name":"spender",
                        "type":"address"
                     },
                     {
                        "internalType":"uint256",
                        "name":"value",
                        "type":"uint256"
                     },
                     {
                        "internalType":"uint256",
                        "name":"deadline",
                        "type":"uint256"
                     },
                     {
                        "internalType":"uint8",
                        "name":"v",
                        "type":"uint8"
                     },
                     {
                        "internalType":"bytes32",
                        "name":"r",
                        "type":"bytes32"
                     },
                     {
                        "internalType":"bytes32",
                        "name":"s",
                        "type":"bytes32"
                     }
                  ],
                  "name":"permit",
                  "outputs":[
                     
                  ],
                  "stateMutability":"nonpayable",
                  "type":"function"
               }
            ],
            "calls":[
               {
                  "reference":"permit",
                  "methodName":"permit",
                  "methodParameters":[
                     "0x0C7ebAC9957C01F0b891B912895A811338aF4Ae0",
                     "0x02af0F2eE01523357B11cBb1B86BA66eb8D2bfED",
                     {
                        "type":"BigNumber",
                        "hex":"0x01"
                     },
                     {
                        "type":"BigNumber",
                        "hex":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
                     },
                     28,
                     "0xef92a36fc7c2fa26ee4275d73918f03ae651708377026c4e936c76f39f9327ca",
                     "0x0b2d9ef10de8200043ffccd2be22e68ef94efe96a1411dbff3aa57b913957da0"
                  ]
               }
            ]
         },
         "callsReturnContext":[
            {
               "returnValues":"0x",
               "decoded":false,
               "reference":"permit",
               "methodName":"permit",
               "methodParameters":[
                  "0x0C7ebAC9957C01F0b891B912895A811338aF4Ae0",
                  "0x02af0F2eE01523357B11cBb1B86BA66eb8D2bfED",
                  {
                     "type":"BigNumber",
                     "hex":"0x01"
                  },
                  {
                     "type":"BigNumber",
                     "hex":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
                  },
                  28,
                  "0xef92a36fc7c2fa26ee4275d73918f03ae651708377026c4e936c76f39f9327ca",
                  "0x0b2d9ef10de8200043ffccd2be22e68ef94efe96a1411dbff3aa57b913957da0"
               ],
               "success":true
            }
         ]
      }
   },
   "blockNumber":8374483
}

The execution of: hre.ethers.provider.getBlock(results.blockNumber)

{
  hash: '0xb6ea7d514f8b7964a1e0a1a8c37b10cae160c32ad6e8a16689d4acda766a2ace',
  parentHash: '0x642723ef33389137adf06538431ec150f7bec04bb82e23723a78190532457477',
  number: 8374483,
  timestamp: 1674659052,
  nonce: '0x0000000000000000',
  difficulty: 0,
  gasLimit: BigNumber { value: "30000000" },
  gasUsed: BigNumber { value: "3196874" },
  miner: '0xf36F155486299eCAff2D4F5160ed5114C1f66000',
  extraData: '0x',
  transactions: [
    '0xf21146d6ee3ba5588f9d9b1ea40064dfd64897a6b496de0eeb49d9916d3add4f',
    '0xa14b09654b83657d54aaa2501ded1fdb869e08889cccf415f22daf26a55de6e5',
    '0x86e64c989291efd4fde735d1ef416abb195808696744357d13289c2fe789a41b',
    '0xc98927934e5e40787f9d715288ff246d04f1279415bc188880e39a9433f5b0f0',
    '0x96d34d26b0638e15d7cf124db4e752ac3f8a17340558aadcf3f8a73adcfd26d6',
    '0x27b2b5a598a27d3a5777b79fedb8181912fc72ad247deffacd603acbeeb965a7',
    '0xfb8a868734effabec77cadc3a2ae5f843312863493b5f72491fc13a420fb2ff9',
    '0x722452c2fa698cf1296eb43a7f5ee345985ba7be88f14f22cf085a0f2089a610',
    '0x2c4d81baeb0a042ad408b5efcd990add45442a9eb6ba49b34efb99275e5f989e',
    '0x023edeecba8bb5671f27920aea063eb54935c2bfa028b2be716866d43631c952'
  ],
  baseFeePerGas: BigNumber { value: "132" },
  _difficulty: BigNumber { value: "0" }
}

swapExactETHForTokens transaction

How can I convert the following transaction to work in a multicall?

var contract = new web3.eth.Contract(routerAbi, routerAddress);
var swapETHforTokens = contract.methods.swapExactETHForTokens(0, [WBNB, tokenAddress], WalletAddress, timeStamp);
var encodedABI = swapETHforTokens.encodeABI();
var swapETHforTokensTX = {
   from: WalletAddress,
   to: routerAddress,
   gas: 176024,
   data: encodedABI,
   value: web3.utils.toWei(ETHtoSell, 'ether'),
};

No problem calling it with eth.call:

await web3.eth
   .call(swapETHforTokenstx, 'pending')
   .then((result) => {
      console.log(web3.eth.abi.decodeLog([{ 'internalType': 'uint256[]', 'name': 'amounts', 'type': 'uint256[]' }], result).amounts[1]);
   })
   .catch((revertReason) => console.log(revertReason));

Multicall get balances of a native currency in a wallet

Hi, I would like to ask how can I get balance of a native token in a wallet. Like the below code,

import {ContractCallContext, Multicall,} from 'ethereum-multicall';
import {ethers} from 'ethers';
import ERC20_ABI from './abi.json' assert {type: 'json'}

let provider = ethers.getDefaultProvider("https://polygon-rpc.com/");

try {
    const walletAddress = "0xe7804c37c13166fF0b37F5aE0BB07A3aEbb6e245"
    const tokenAddresses = ["0x0000000000000000000000000000000000000000"]
    const network = await provider.getNetwork()
    // you can use any ethers provider context here this example is
    // just shows passing in a default provider, ethers hold providers in
    // other context like wallet, signer etc all can be passed in as well.
    const multicall = new Multicall({ ethersProvider: provider, tryAggregate: true });

    const contractCallContext: ContractCallContext[] = tokenAddresses.map((it) => ({
        reference: `${it}`,
        contractAddress: it,
        abi: ERC20_ABI,
        calls: [{ reference: `callBalanceOf:${it}`, methodName: 'balanceOf', methodParameters: [walletAddress] }],
    }))
    const callResults = await multicall.call(contractCallContext)
    const tokenBalancesMap = {} as Record<string, bigint>
    for (const address in callResults.results) {
        try {
            tokenBalancesMap[address] = BigInt(callResults.results[address].callsReturnContext[0].returnValues[0].hex)
        } catch (e) {
            console.warn(`parsing token balance from multicall failed for token ${address} in chain ${network.chainId}`)
        }
    }
    console.log(tokenBalancesMap)
}catch (e) {
    console.error('!-- ERROR:', e)
    console.log('Is there anything to inspect?')
} finally {
}
  • input: token address as null address
  • output: empty object. For more info, if I set tryAggregate to false, the error would be
ERROR: Error: data out-of-bounds (length=0, offset=32, code=BUFFER_OVERRUN, version=abi/5.7.0)

In the particular case is polygon chain, I can replace null address with matic token address 0x0000000000000000000000000000000000001010, and it works well. But if moving to another chain like Ethereum and BNB, there are no address like that but the null address.
How could I call get balance of a native currency for a wallet in such chains? On the other hand, in the library https://github.com/indexed-finance/multicall?tab=readme-ov-file#querying-token-balances, I could able to get balance with null address.

Thank you and have a great day.
P.S: Really appreciate your multicall package, and wishes you have awesome features in the future.

Uncaught (in promise) Error: invalid address (argument="address", value=0, code=INVALID_ARGUMENT, version=address/5.7.0) (argument=null, value=0, code=INVALID_ARGUMENT, version=abi/5.7.0)

Hello,

First of all thank you for putting together ethereum-multicall for us, really appreciate it.

I am running into an issue on my react js code when trying to call multicall.
The issue looks like this:

Uncaught (in promise) Error: invalid address (argument="address", value=0, code=INVALID_ARGUMENT, version=address/5.7.0) (argument=null, value=0, code=INVALID_ARGUMENT, version=abi/5.7.0)

I have double checked the addresses and they are correct and they worked when not trying to use multiCall.

The following is my code on how I am calling multiCall

async loadDataUsingMulticall() {
    const { web3 } = this.state;
    var multicall = null;
    console.log("This is the mirror address:",MIRROR_ADDRESS);


    multicall = new Multicall({
      multicallCustomContractAddress: MIRROR_ADDRESS,
      nodeUrl: BSC_RPC_URL,
      web3Instance: web3,
      tryAggregate: true,
    });

    console.log("test zero");

    const contractCallContext = [
      {
        reference: "mirrorBalance",
        contractAddress: MIRROR_ADDRESS,
        abi: MIRRORABI,
        calls: [
          {
            methodName: "balanceOf",
            methodParameters: [this.state.account[0]],
          },
        ],
      },
      {
        reference: "morWholeBurn",
        contractAddress: MIRROR_ADDRESS,
        abi: MIRRORABI,
        calls: [
          {
            methodName: "balanceOf",
            methodParameters: ["0x0000000000000000000000000000000000000000"],
          },
        ],
      },
      {
        reference: "morRFIBurn",
        contractAddress: MIRROR_ADDRESS,
        abi: MIRRORABI,
        calls: [
          {
            methodName: "balanceOf",
            methodParameters: ["0x000000000000000000000000000000000000dead"],
          },
        ],
      },
      {
        reference: "totalFees",
        contractAddress: MIRROR_ADDRESS,
        abi: MIRRORABI,
        calls: [{ methodName: "totalFees", methodParameters: [] }],
      },
      {
        reference: "numFarmers",
        contractAddress: MIRROR_ADDRESS,
        abi: MIRRORABI,
        calls: [{ methodName: "numFarmers", methodParameters: [] }],
      },
    ];

    console.log("test before");
    console.log(MIRROR_ADDRESS);

    // Loop for dynamic method calls like 'farmers' and 'farmingLeaderboard'
    for (let i = 0; i < 5; i++) {
      contractCallContext.push({
        reference: `farmer${i}`,
        contractAddress: MIRROR_ADDRESS,
        abi: MIRRORABI,
        calls: [{ methodName: "farmers", methodParameters: [i] }],
      });
      contractCallContext.push({
        reference: `farmer${i}amt`,
        contractAddress: MIRROR_ADDRESS,
        abi: MIRRORABI,
        calls: [{ methodName: "farmingLeaderboard", methodParameters: [i] }],
      });
    }
    ////////////

    const callResults = await multicall.call(contractCallContext);
    console.log("test)");
    console.log(callResults);

    
    // Accessing individual results
    const mirrorBalance = Web3.utils.fromWei(
      callResults.results.mirrorBalance.callsReturnContext[0].returnValues[0],
      "ether",
    );
    const morWholeBurn = Web3.utils.fromWei(
      callResults.results.morWholeBurn.callsReturnContext[0].returnValues[0],
      "ether",
    );
    const morRFIBurn = Web3.utils.fromWei(
      callResults.results.morRFIBurn.callsReturnContext[0].returnValues[0],
      "ether",
    );
    const totalFees = Web3.utils.fromWei(
      callResults.results.totalFees.callsReturnContext[0].returnValues[0],
      "ether",
    );
    const numFarmers = parseInt(
      callResults.results.numFarmers.callsReturnContext[0].returnValues[0],
    );
    console.log("This is mirror Balance");
    console.log(mirrorBalance);
    console.log("This is morWhole Burn");
    console.log(morWholeBurn);
    console.log("This is total Farmers");
    console.log(numFarmers);
    // Loop to access farmers and farmingLeaderboard data
    let farmerData = {};
    for (let i = 0; i < 5; i++) {
      farmerData[`farmer${i}`] =
        callResults.results[`farmer${i}`].callsReturnContext[0].returnValues[0];
      farmerData[`farmer${i}amt`] =
        callResults.results[
          `farmer${i}amt`
        ].callsReturnContext[0].returnValues[0];
    }

    // Update state with all the gathered data
    this.setState({
      mirrorBalance,
      morWholeBurn,
      morRFIBurn,
      totalFees,
      numFarmers,
      ...farmerData,
      loadingLeaderBoard: false,
    });
  }

feature request: upgrade to Multicall3

Looks like you currently maintain a hardcoded mapping of networks to addresses, and need to deploy a new contract and update that for each chain users want supported. If you migrate to Multicall3 you'll support more chains with less maintenance (I'm biased of course, but I do think it'll be easier for you).

It's fully backwards compatible, and adds a few new methods to offer users more granularity over reverting calls.

Looks like etherlite is the only chain Multicall3 isn't deployed on that this lib currently supports: if people actually use that and you need to maintain compatibility, we just need someone to fund to the Multicall3 deployer account (0x05f32B3cC3888453ff71B01135B34FF8e41263F2) and I can deploy it on that chain.

use custom contract address

I want to use the contract that I deploy on okexchain, but there is something wrong:
image
if I open the 'tryAggregate'
image
if turn off 'tryAggregate', I can get a result,bug the balance of token is wrong
image
image

can u tell me how can use a custom contract?

Does the repository support ethers ^6.6.0

I am using

const { Multicall } = require("ethereum-multicall");
const poolABI = require('./utils/uniswapPairV2ABI.json');
const { ethers } = require("ethers");
const { wsURL } = require("./config.js");
const { Web3 } = require("web3");

const rpcURL = "My RPC URL";
// const web3 = new Web3(rpcURL);
const calls = [
    { methodName: 'token0', methodParameters: [] },
    { methodName: 'token1', methodParameters: [] },
    { methodName: 'factory', methodParameters: [] }
];

// A pair address
const contractAddress = "0xB6909B960DbbE7392D405429eB2b3649752b4838";

const callObject = {
    reference: "result0",
    contractAddress: contractAddress,
    abi: poolABI,
    calls: calls
};

const provider = new ethers.JsonRpcProvider(rpcURL);
console.log(provider);

const myMulticall = new Multicall({
    ethersProvider: provider,
    tryAggregate: true,
});
async function getResult() {
    let resp = await myMulticall.call(callObject);
    console.log(resp.results.result0.callsReturnContext);

}
getResult();

It throws out the error
Error: invalid signer or provider (argument="signerOrProvider", value={}, code=INVALID_ARGUMENT, version=contracts/5.7.0)

The ethers version is 6.6.1. I want to ask if the error is caused by the version conflict.

How to get eth call data

I need the hex data to use my custom eth_call like:
image

So instead of using multicall.call(), I just want to get hex data.

Have any methods there to do this?

Multicall do not run in BSC TESTNET

  • I use muticall to call in bsc testnet with web3js but it cause a error Error: Returned error: execution reverted.
  • I am sure my contract address and ABI is correct because I am able to call this contract without muticall.

Could anyone tell me if I missed anything?

function symbol returns empty

I'm trying to understand how this module works.
This is my ContractCallContext:

  {
        reference: 'testContract',
        contractAddress: '0xCc7bb2D219A0FC08033E130629C2B854b7bA9195',
        abi: [        {
            name: "symbol",
            type: "function",
            inputs: [{name: "", type: 'string'}],
            outputs: [
                {
                    name: "",
                    type: "string"
                }
            ],
            stateMutability: "view",

        },],
        calls: [{ reference: 'symbolCall', methodName: 'symbol', methodParameters: [42] }]
    }

returns this:

callsReturnContext: [
    {
      returnValues: [],
      decoded: false,
      reference: 'symbolCall',
      methodName: 'symbol',
      methodParameters: [Array],
      success: false
    }
  ]

What am I doing wrong?
Could you also show me an example of something more complex like erc20 token approval and swap?

thanks for this module.

Accessing Multicall3 Contract Methods

I am trying to access the build in multicall3 method getCurrentBlockTimestamp() using the following ABI

[
      {      
        inputs: [],
        name: "getCurrentBlockTimestamp",
        outputs: [
          {
            internalType: "uint256",
            name: "",
            type: "uint256"
          }
        ],
        stateMutability: "view",
        type: "function"
      }
  ]

with the following call in my contractCallContext

             { reference: 'blockTime', methodName: 'getCurrentBlockTimestamp', methodParameters: null }

Unfortunately I get the error:

rror: call revert exception; VM Exception while processing transaction: reverted with reason string "Multicall3: call failed" [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="aggregate((address,bytes)[])", data="0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000174d756c746963616c6c333a2063616c6c206661696c6564000000000000000000", errorArgs=["Multicall3: call failed"], errorName="Error", errorSignature="Error(string)", reason="Multicall3: call failed", code=CALL_EXCEPTION, version=abi/5.7.0)

How can I access the build in multicall contract methods? I cannot find anything in the readme

Archive data request

If i get request for multicall data on specific block wich happened in 2023 i getting result as i should, but if i request data for Eth from 2019 im getting this error:

Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="tryBlockAndAggregate(bool,(address,bytes)[])", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.7.0)
at Logger.makeError (index.ts:269:1)
at Logger.throwError (index.ts:281:1)
at Interface.decodeFunctionResult (interface.ts:427:1)
at Object. (index.ts:400:1)
at Generator.next ()
at fulfilled (index.ts:1:1)

Is this because there is no data for that time so i can return emty result or i making some mistake.? I'm using this multicontractAddress : 0xcA11bde05977b3631167028862bE2a173976CA11
Also im using Merkle as provider

Custom block number

Love the library, thank you for sharing!

Is there any way to request information from a specific block number?
this example code gets your token balance from 4 days ago compared to now

    const blocksAgo = n => provider.getBlockNumber().then(b => b - n);
    let blockNumber = await blocksAgo(30000);

    const tokenContract = new Contract(tokenAddress, erc20Abi);
    let balance1 = await tokenContract.balanceOf(address, 'latest');
    console.log(`latestBalance: ${ethers.utils.formatEther(balance1)}`);
    let balance2 = await tokenContract.balanceOf(address, blockNumber);
    console.log(`prevBalance: ${ethers.utils.formatEther(balance2)}`);

Uncaught (in promise) Error: network does not support ENS (operation="ENS", network="unknown", code=UNSUPPORTED_OPERATION, version=providers/5.1.2)

Hello try to using it on browser via vue.js but got error :
index.js?ffb2:166 Uncaught (in promise) Error: network does not support ENS (operation="ENS", network="unknown", code=UNSUPPORTED_OPERATION, version=providers/5.1.2)
at Logger.makeError (index.js?ffb2:166)
at Logger.throwError (index.js?ffb2:175)
at JsonRpcProvider.eval (base-provider.js?bc79:1244)
at Generator.next ()
at fulfilled (base-provider.js?bc79:5)

Is it because doesnt support on browser ?

here is my initialization :

const ethersProvider = new providers.getDefaultProvider('https://bsc-dataseed1.binance.org');
    const multicall = new Multicall({ ethersProvider: ethersProvider, multicallCustomContractAddress: '0x1Ee38d535d541c55C9dae27B12edf090C608E6Fb' });

UnhandledPromiseRejectionWarning: Error: Returned error: out of gas

This code returns "UnhandledPromiseRejectionWarning: Error: Returned error: out of gas".

Any idea why?

const { Multicall } = require('ethereum-multicall');
const Web3 = require('web3');
const { abi } = require('../metadata/abi');

const options = {
  timeout: 10000, // ms
  reconnect: { auto: true, delay: 1000,  maxAttempts: 5, onTimeout: false }
};
const provider = new Web3.providers.HttpProvider('ADDRESS HERE');
const web3 = new Web3(provider, options);
const multicall = new Multicall({ web3Instance: web3, tryAggregate: true});

async function main() {
  const tokenIDs = Array.from({length: 296}, (_, i) => i + 1900);
  const calls = tokenIDs.map((token_id) => { return { methodName: 'tokenByIndex', methodParameters: [token_id] }; });
  const contractCallContext = [{ reference: 'contract', contractAddress: '0x160c404b2b49cbc3240055ceaee026df1e8497a0', abi, calls}];
  const results = await multicall.call(contractCallContext);
  const extract = results.results.contract.callsReturnContext.map((r) => r.success ? web3.utils.hexToNumber(r.returnValues[0].hex) : null);
  console.log(extract);
}

main();

Full unit tests

Did not have time to cover this with unit tests so when I get time make sure we cover the lot before it's used in many projects.

returnValues is an array of values instead of an array of objects

Hey everyone.
I've encountered an issue where after the multicall, the returnValues prop in the callsReturnContext item is an array (of bignums in my case), instead of an array of objects with key/value pairs.
It's the first time I've encountered such an issue because I've always used this lib for multicalls but it turned out that all of those always had a singular return, meaning that they returned one value and not a collection.
The ABI is correct, I triple checked. Everything works as expected if I call the contract directly.
I'm providing screenshots for context, however, if those are not enough - please let me know, I'll create a codepen demo.

Screenshot 2023-04-25 at 23 16 26

Screenshot 2023-04-25 at 23 17 17

Screenshot 2023-04-25 at 23 17 57

Screenshot 2023-04-25 at 23 18 43

Using Multicall with ethers Wallet

Hi,

The comment in the code snippet says that

...ethers hold providers in other context like wallet, signer etc all can be passed in as well.

So, I assumed that the following code is correct

const provider = new ethers.providers.JsonRpcProvider(process.env.NETWORK_URL);
const wallet = new ethers.Wallet(process.env.ACCOUNT).connect(provider);
const multicall = new ethereumMulticall.Multicall({ ethersProvider: wallet , tryAggregate: true });

But I'm, getting

UnhandledPromiseRejectionWarning: TypeError: ethersProvider.getNetwork is not a function

What am I missing? How can use Multicall with Wallet?

Thank you

Ethereum wallet for donate

Public pls your ETH wallet. Good way for donate.
You doing perfectly work, and save time of developers:)

tryAggregate fails when there's an error decoding.

I'm trying to get a list of tokens for a user's wallet, and there's a contract that is likely malformed. The blockchain call works, but when multicall tries to decode with the ABI (symbol, balanceOf, name, decimals, totalSupply) it fails w/ a data out of bounds error:
Error: data out-of-bounds (length=0, offset=32, code=BUFFER_OVERRUN, version=abi/5.5.0)

If we just wrapped the ABI decode portion of multicall.js with a try/catch, we could still get the expected behavior of aggregation despite what happens during calls to the network and decoding.

Here's the token (it's a Uniswap v2 LP token):
https://etherscan.io/token/0xfb072e4dE3719E84503b3fB303173Dd6D29aB472#readContract

When I call the same methods manually they work

invalid address

Hi, I got this error:

Uncaught (in promise) Error: invalid address (argument="address", value=42, code=INVALID_ARGUMENT, version=address/5.4.0) (argument="_owner", value=42, code=INVALID_ARGUMENT, version=abi/5.4.0)
at Logger.makeError (swapv1.1.1.f4473701.js:66157)
at Logger.throwError (swapv1.1.1.f4473701.js:66166)
at Logger.throwArgumentError (swapv1.1.1.f4473701.js:66169)
at AddressCoder._throwError (swapv1.1.1.f4473701.js:149229)
at AddressCoder.encode (swapv1.1.1.f4473701.js:149357)
at swapv1.1.1.f4473701.js:149419
at Array.forEach ()
at Object.pack (swapv1.1.1.f4473701.js:149407)
at TupleCoder.encode (swapv1.1.1.f4473701.js:149782)
at AbiCoder.encode (swapv1.1.1.f4473701.js:149169)

`const multicall = new Multicall({ ethersProvider: provider, tryAggregate: true });

const contractCallContext: ContractCallContext<{extraContext: string, foo4: boolean}>[] = [
    {
        reference: 'testContract',
        contractAddress: '0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4',
        abi: Abi,
        calls: [{ reference: 'fooCall', methodName: 'balanceOf', methodParameters: [42] }],

    },
    {
        reference: 'testContract2',
        contractAddress: '0x1a13f4ca1d028320a707d99520abfefca3998b7f',
        abi: Abi,
        calls: [{ reference: 'fooTwoCall', methodName: 'balanceOf', methodParameters: [42] }]
    }
];

const results: ContractCallResults = await multicall.call(contractCallContext);
console.log(results);

}`

can you help me?

Block-Specific Multicall

Is it possible to pass a block parameter to the multicall in order to execute queries at that specific block height?

In Ethers, a single query can be executed with a blocktag ({ blockTag: blockNumber }) in order to accomplish this.

Having similar functionality on multicalls would be incredible.

Multicall fails on Arbitrum for most RPCs

When I try to perform a multicall on Arbitrum, most RPCs will return this error:
console.error("getUniswapV3PairPrice ERROR", networkId, e)
The only RPC I've tried that does work on Arbitrum is: https://arb1.arbitrum.io/rpc
On other networks (I tried mainnet, Optimism and Goerli) the multicalls work perfectly.

I create my multicall instances like this:
const multicall = new Multicall({ web3Instance: web3, tryAggregate: true });
With web3 here being new Web3(myRpcUrl). I have also tried using nodeUrl: myRpcUrl instead of web3Instance, to no avail.

Multicall2 (tryAggregate) missing from Matic

It seems that the variant that allows for failing calls wasn't yet deployed to Matic/Mumbai. The official maker repo doesn't include addresses for Multicall2 and the file with configurations in the library unfortunately mixes the usage of v1 and v2.

As a heads up for anyone using the aggregate variant, don't forget to manually reference a multicall2 contract in the constructor. If you want to use something already deployed, I've added them on Matic and Mumbai if anyone wants to use them there:

Matic: 0x275617327c958bd06b5d6b871e7f491d76113dd8
Mumbai: 0xe9939e7Ea7D7fb619Ac57f648Da7B1D425832631

P.S. Great work with the library, was really useful!

ethers.js Signer TypeError: ethersProvider.getNetwork

Use ethers.js

new Multicall({ ethersProvider: new providers.Web3Provider((window as any).ethereum), tryAggregate: true })

Get error:
TypeError: ethersProvider.getNetwork is not a function

PS: Metamask wallet connected

Cleanup non issue

When my account was compromised a spam issue was created in this repo. I sincerely apologize. Cleaning up such issues via script.

Polygon zkEvm Mainnet blocNumber issue

Screenshot_1
Hello, hello, it's me again. :/ For some reason, whenever I request balances for Polygon zkEvm byBlockNumber using multicall, it always returns block+1 for the given block. Here's the script so you can debug it. Also, how i can provide chainId to my request to avoid unneeded request get_chainId? As you can see im using "0xca11bde05977b3631167028862be2a173976ca11" for mutlicall smart contract address and "https://rpc.ankr.com/polygon_zkevm" for provider.

import {
Multicall,
ContractCallResults,
ContractCallContext,
} from "ethereum-multicall";

import { NetworkCoinToken } from "../models/models";

export const GetFinalResultv2 = async () => {
let tokens: any[] = [
{
id: 2452,
name: "ChainLink Token",
shortName: "LINK",
contractAddress: "0x4b16e4752711a7abec32799c976f3cefc0111f2b",
networkId: 40,
},
{
id: 2465,
name: "Ankr Staked ETH",
contractAddress: "0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c",
networkId: 40,
},
];
const walletAddress = "0xA9D1e08C7793af67e9d92fe308d5697FB81d3E43";
const contractCallContext: ContractCallContext[] = tokens.map(
(token: NetworkCoinToken) => ({
reference: token.contractAddress || "",
context: token.name,
contractAddress: token.contractAddress || "",
abi: [
{
name: "balanceOf",
type: "function",
stateMutability: "view",
inputs: [
{
name: "_owner",
type: "address",
},
],
outputs: [
{
name: "balance",
type: "uint256",
},
],
},
],
calls: [
{
reference: token.contractAddress || "",
methodName: "balanceOf",
methodParameters: [walletAddress || ""],
},
],
})
);
const multicall = new Multicall({
tryAggregate: true,
multicallCustomContractAddress:
"0xca11bde05977b3631167028862be2a173976ca11",
nodeUrl: "https://rpc.ankr.com/polygon_zkevm",
});
const getData = async () => {
let resultData: ContractCallResults | null = null;
try {
const numberBl = "10275514";
resultData = await multicall.call(contractCallContext, {
blockNumber: numberBl,
});

		if (resultData) {
			console.log("Provided block number", numberBl);
			console.log(resultData);
			return resultData;
		}
	} catch (error: any) {
		console.log(error);
	}
};
const finalData: any = (await getData()) || [];
return finalData;

};

Error when executing huge batches

Executing batches of huge sizes 300++ seems to throw an error. Suspect it has to do with timeout variable? Smaller batches with the same logic does not throw any errors.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.