Web3j
如何使用 Web3j 呼叫 Multicall Contract?
我需要使用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();