Web3j

如何使用 Web3j 呼叫 Multicall Contract?

  • March 15, 2021

我需要使用Multi Call合約來合併多個呼叫,它在主網上的地址是0x2cc8688C5f75E365aaEEb4ea8D6a480405A48D2A

contract Multicall {
struct Call {
   address target;
   bytes callData;
}
function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) {
   blockNumber = block.number;
   returnData = new bytes[](calls.length);
   for(uint256 i = 0; i < calls.length; i++) {
       (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);
       require(success);
       returnData[i] = ret;
   }
}
...
}

當我請求空值時,我可以得到正常的返回結果。

    Web3j web3j = new Web3Helper("wss://mainnet.infura.io/ws/v3/xxxx").getWeb3j();
   String addressOfMulticall = "0xeefba1e63905ef1d7acba5a8513c70307c1ce441";
   //create an empty struct data
   StaticStruct staticStruct = new StaticStruct(Address.DEFAULT, new DynamicBytes(new byte[0]));
   Function function = new Function("aggregate", List.of(new DynamicArray(StaticStruct.class, staticStruct))
           , List.of(new TypeReference<StaticStruct>() {
   }));
   String encodeFunctionDataOfMulticall = FunctionEncoder.encode(function);
   //encodeFunctionDataOfMulticall-> 0x252dba420000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
   //buildMethodSignature -> aggregate((address,bytes)[])
   //buildMethodId -> 0x252dba42
   //create an eth_call transaction
   Transaction ethCallTransaction = Transaction.createEthCallTransaction(Address.DEFAULT.getValue(), addressOfMulticall, encodeFunctionDataOfMulticall);
   EthCall send = web3j.ethCall(ethCallTransaction, DefaultBlockParameterName.PENDING).sendAsync().get();
   //Sending request: {"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","to":"0x942EEB04AD50500a970d71a374101Ee78F87FB53","data":"0xaf36778b"},"pending"],"id":0}
   //Received message {"jsonrpc":"2.0","id":0,"result":"0x0000000000000000000000000000000000000000000000000000000000b76dd40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"}

當我傳遞的值不為空時,EVM執行會報錯。

Web3j web3j = new Web3Helper("wss://mainnet.infura.io/ws/v3/xxxx").getWeb3j();
   String addressOfMulticall = "0xeefba1e63905ef1d7acba5a8513c70307c1ce441";
   Address addressOfDaiTokens = new Address("0x6b175474e89094c44da98b954eedeac495271d0f");
   //solidity code: function name() returns(string memory){}
   Function nameFunction = new Function("name", List.of(), List.of(new TypeReference<DynamicBytes>() {
   }));
   String encodeDataOfNameFunction = FunctionEncoder.encode(nameFunction);
   //encodeDataOfNameFunction->0x06fdde03
   StaticStruct staticStruct = new StaticStruct(addressOfDaiTokens, new DynamicBytes(encodeDataOfNameFunction.getBytes()));
   //solidity code: function aggregate(Call[]); Call{address,bytes};
   Function aggregateFunction = new Function("aggregate", List.of(new DynamicArray(StaticStruct.class, staticStruct))
           , List.of(new TypeReference<StaticStruct>() {
   }));
   String encodeFunctionDataOfMulticall = FunctionEncoder.encode(aggregateFunction);
   //encodeFunctionDataOfMulticall-> 0x252dba42000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000000000000000000000a3078303666646465303300000000000000000000000000000000000000000000
   //buildMethodSignature -> aggregate((address,bytes)[])
   //buildMethodId -> 0x252dba42
   //create an eth_call transaction
   Transaction ethCallTransaction = Transaction.createEthCallTransaction(Address.DEFAULT.getValue(), addressOfMulticall, encodeFunctionDataOfMulticall);
   EthCall send = web3j.ethCall(ethCallTransaction, DefaultBlockParameterName.PENDING).sendAsync().get();
   //Sending request: {"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","to":"0xeefba1e63905ef1d7acba5a8513c70307c1ce441","data":"0x252dba42000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000000000000000000000a3078303666646465303300000000000000000000000000000000000000000000"},"pending"],"id":0}
   //Received message {"jsonrpc":"2.0","id":0,"error":{"code":-32000,"message":"execution reverted"}}

我想知道如何對相應的數據進行編碼以獲得正常的回報。有人可以幫幫我嗎?

將程式碼中的StaticStruct替換為DynamicStruct就可以解決這個錯誤。同時需要注意如何傳遞encoded bytes參數。而且web3j版本是4.8.4。在5.0.0版本的web3j中, Struct 的相關類已替換為 Tuple。

   Web3j web3j = new Web3Helper("wss://kovan.infura.io/ws/v3/xxxx").getWeb3j();
   String addressOfMulticall = "0x1aA360cdfEeae06D4ac2686fb44Dc2B804Abf2dC";
   Address addressOfDaiTokens = new Address("0xd0a1e359811322d97991e03f863a0c30c2cf029c");
   Function nameFunction = new Function("name", List.of(), List.of(new TypeReference<DynamicBytes>() {
   }));
   String encodeDataOfNameFunction = FunctionEncoder.encode(nameFunction);
   /**
    * before: StaticStruct staticStruct = new StaticStruct(addressOfDaiTokens, new DynamicBytes(encodeDataOfNameFunction.getBytes()));
    */
   DynamicStruct staticStruct = new DynamicStruct(addressOfDaiTokens, new DynamicBytes(Hex.decode(encodeDataOfNameFunction.substring(2).getBytes())));
   Function aggregateFunction = new Function("aggregate", List.of(new DynamicArray(DynamicStruct.class, staticStruct))
           , List.of(new TypeReference<Uint256>() {
   }, new TypeReference<DynamicArray<DynamicBytes>>() {
   }));
   String encodeFunctionDataOfMulticall = FunctionEncoder.encode(aggregateFunction);
   Transaction ethCallTransaction = Transaction.createEthCallTransaction(Address.DEFAULT.getValue(), addressOfMulticall, encodeFunctionDataOfMulticall);
   EthCall send = web3j.ethCall(ethCallTransaction, DefaultBlockParameterName.PENDING).sendAsync().get();

引用自:https://ethereum.stackexchange.com/questions/94511