Skip to content

Commit

Permalink
feat: Multicall v2 (pancakeswap#1436)
Browse files Browse the repository at this point in the history
* feat: Multicall v2

* refactor: Remove useless try/catch
  • Loading branch information
hachiojidev authored Jun 4, 2021
1 parent 033f87f commit ab5fe96
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 24 deletions.
155 changes: 133 additions & 22 deletions src/config/abi/Multicall.json
Original file line number Diff line number Diff line change
@@ -1,54 +1,165 @@
[
{
"constant": true,
"inputs": [
{
"components": [
{
"name": "target",
"type": "address"
},
{
"name": "callData",
"type": "bytes"
}
{ "internalType": "address", "name": "target", "type": "address" },
{ "internalType": "bytes", "name": "callData", "type": "bytes" }
],
"internalType": "struct Multicall2.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "aggregate",
"outputs": [
{ "internalType": "uint256", "name": "blockNumber", "type": "uint256" },
{ "internalType": "bytes[]", "name": "returnData", "type": "bytes[]" }
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "blockNumber",
"type": "uint256"
},
"components": [
{ "internalType": "address", "name": "target", "type": "address" },
{ "internalType": "bytes", "name": "callData", "type": "bytes" }
],
"internalType": "struct Multicall2.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "blockAndAggregate",
"outputs": [
{ "internalType": "uint256", "name": "blockNumber", "type": "uint256" },
{ "internalType": "bytes32", "name": "blockHash", "type": "bytes32" },
{
"components": [
{ "internalType": "bool", "name": "success", "type": "bool" },
{ "internalType": "bytes", "name": "returnData", "type": "bytes" }
],
"internalType": "struct Multicall2.Result[]",
"name": "returnData",
"type": "bytes[]"
"type": "tuple[]"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "uint256", "name": "blockNumber", "type": "uint256" }],
"name": "getBlockHash",
"outputs": [{ "internalType": "bytes32", "name": "blockHash", "type": "bytes32" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getBlockNumber",
"outputs": [{ "internalType": "uint256", "name": "blockNumber", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockCoinbase",
"outputs": [{ "internalType": "address", "name": "coinbase", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockDifficulty",
"outputs": [{ "internalType": "uint256", "name": "difficulty", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockGasLimit",
"outputs": [{ "internalType": "uint256", "name": "gaslimit", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockTimestamp",
"outputs": [{ "internalType": "uint256", "name": "timestamp", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "addr", "type": "address" }],
"name": "getEthBalance",
"outputs": [{ "internalType": "uint256", "name": "balance", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getLastBlockHash",
"outputs": [{ "internalType": "bytes32", "name": "blockHash", "type": "bytes32" }],
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "internalType": "bool", "name": "requireSuccess", "type": "bool" },
{
"name": "addr",
"type": "address"
"components": [
{ "internalType": "address", "name": "target", "type": "address" },
{ "internalType": "bytes", "name": "callData", "type": "bytes" }
],
"internalType": "struct Multicall2.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "getEthBalance",
"name": "tryAggregate",
"outputs": [
{
"name": "balance",
"type": "uint256"
"components": [
{ "internalType": "bool", "name": "success", "type": "bool" },
{ "internalType": "bytes", "name": "returnData", "type": "bytes" }
],
"internalType": "struct Multicall2.Result[]",
"name": "returnData",
"type": "tuple[]"
}
],
"payable": false,
"stateMutability": "view",
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "bool", "name": "requireSuccess", "type": "bool" },
{
"components": [
{ "internalType": "address", "name": "target", "type": "address" },
{ "internalType": "bytes", "name": "callData", "type": "bytes" }
],
"internalType": "struct Multicall2.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "tryBlockAndAggregate",
"outputs": [
{ "internalType": "uint256", "name": "blockNumber", "type": "uint256" },
{ "internalType": "bytes32", "name": "blockHash", "type": "bytes32" },
{
"components": [
{ "internalType": "bool", "name": "success", "type": "bool" },
{ "internalType": "bytes", "name": "returnData", "type": "bytes" }
],
"internalType": "struct Multicall2.Result[]",
"name": "returnData",
"type": "tuple[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
4 changes: 2 additions & 2 deletions src/config/constants/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export default {
56: '',
},
multiCall: {
56: '0x1ee38d535d541c55c9dae27b12edf090c608e6fb',
97: '0x67ADCB4dF3931b0C5Da724058ADC2174a9844412',
56: '0xfF6FD90A470Aaa0c1B8A54681746b07AcdFedc9B',
97: '',
},
pancakeProfile: {
56: '0xDf4dBf6536201370F95e06A0F8a7a70fE40E388a',
Expand Down
23 changes: 23 additions & 0 deletions src/utils/multicall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,27 @@ const multicall = async (abi: any[], calls: Call[]) => {
return res
}

/**
* Multicall V2 uses the new "tryAggregate" function. It is different in 2 ways
*
* 1. If "requireSuccess" is false multicall will not bail out if one of the calls fails
* 2. The return inclues a boolean whether the call was successful e.g. [wasSuccessfull, callResult]
*/
export const multicallv2 = async (abi: any[], calls: Call[], requireSuccess = true) => {
const web3 = getWeb3NoAccount()
const multi = new web3.eth.Contract(MultiCallAbi as unknown as AbiItem, getMulticallAddress())
const itf = new Interface(abi)

const calldata = calls.map((call) => [call.address.toLowerCase(), itf.encodeFunctionData(call.name, call.params)])
const returnData = await multi.methods.tryAggregate(requireSuccess, calldata).call()
const res = returnData.map((call, i) => {
const [result, data] = call
return {
result,
data: itf.decodeFunctionResult(calls[i].name, data),
}
})

return res
}
export default multicall

0 comments on commit ab5fe96

Please sign in to comment.