joshstevens19 / ethereum-multicall Goto Github PK
View Code? Open in Web Editor NEWAbility to call many ethereum constant function calls in 1 JSONRPC request
License: MIT License
Ability to call many ethereum constant function calls in 1 JSONRPC request
License: MIT License
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?
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.
It seems like Fantom blockchain is not supported.
Im getting
Returned error: the method net_version does not exist/is not available
Can this library be used for the Tron mainnet?
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')
`
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]] }, ], }
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' },
]
}
]
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" }
}
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));
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 {
}
tryAggregate
to false, the error would beERROR: 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.
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:
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,
});
}
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.
Would be great to add a multicall contract and support natively from this library for Oasis Sapphire
Chain ID: 23294
RPC: https://sapphire.oasis.io
Explorer: https://explorer.sapphire.oasis.io/
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.
On a multicall call on the bsc contract, I get this error : UnhandledPromiseRejectionWarning: Error: Returned error: out of gas
The call was working before, didn't change any. Have any idea where this issue comes from and how I can solve it ?
Error: Returned error: execution reverted
.Could anyone tell me if I missed anything?
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.
Add the ability to specify a generic type for multicall response:
multicall.call<T>
This will enable adding typesafe bindings to contract calls
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
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
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)}`);
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' });
Mulltilcall returns CallValueResult with type:
{
type: "BigNumber",
hex: "0x0176b344f2a78c0000"
},
It doesn't the same type as I call single. This case type is likely { BigNumber } from "ether." It's
{
_isBigNumber: true,
_hex: "0x0176b344f2a78c0000"
},
Could anyone tell me if I missed anything?
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();
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.
Could you deploy to base chain now that it's launched?
https://docs.base.org/network-information
https://www.multicall3.com/deployments
Cheers!
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.
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
Hi Josh,
The BSC Multicall contract used by ethereum-multicall is: https://bscscan.com/address/0xAf379C844f87A7b47EE6fe5E4a9720988EaEA0AF
Are you the one who published the contract? If yes, could you also publish the source? I tried to publish it but it didn't work.
Manta is already live in multicall3, here is the deployment: https://github.com/mds1/multicall/blob/fa4f4dfb435721c0dbc088f54cb82a93bf753069/deployments.json#L733
I've created a PR here: #93
Would be great if you can preview and merge this.
Public pls your ETH wallet. Good way for donate.
You doing perfectly work, and save time of developers:)
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
Hi, I'm looking for a way to swap tokens multiple times in a single transaction, like this transaction.
Do you think it's achievable using Multicall?
Is it planned to make functionality for zkSync Era network ?)
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?
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.
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.
Would it be possible to deploy the Multicall contract on Arbitrum Rinkeby?
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!
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
When my account was compromised a spam issue was created in this repo. I sincerely apologize. Cleaning up such issues via script.
The function globalPositionData
of kovan contract 0xD21d3A321eDc8ca5FEA387A4D082a349c86CCfE5 returns two values but only one of them is being returned when using ethereum-multicall with web3.js.
After a little bit of debugging the problem seems to be the formatReturnValues
function.
I commented out these lines to fix the issue locally:
if (Array.isArray(decodedReturnResults)) {
return decodedReturnResults;
}
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;
};
Take below method for example, it returns 3 uint, but I can only get one from returnValues
function getAccountLiquidity(address account) public view returns (uint, uint, uint) {
}
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.