前言
在使用Java解析UniswapV3链上Input Data数据的时候遇到方法函数multicall(bytes[] calldata data)
的解析失败。后面查找web3.js的方法尝试理解Java的解析。
Tx:
https://etherscan.io/tx/0xecb398ee0e00ec3b3f1bc4d3d34c69153c2abeef995d39a69c1f30300330c18e
Input Data:
0xac9650d800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000104414bf389000000000000000000000000c5e7703d4647ff77bc733bb56d120471b83382e2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006507f7280000000000000000000000000000000000000000000000000001d6c3ef643800000000000000000000000000000000000000000000000000014fcd4e1e5ce130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004449404b7c000000000000000000000000000000000000000000000000014fcd4e1e5ce13000000000000000000000000019edc2f769ac416c725e1c4032be50c1d4b3bd3a00000000000000000000000000000000000000000000000000000000
web3.js解码
let calls = web3.eth.abi.decodeParameters(['bytes[]'], calldata)[0];
console.log(`calls1:${calls}`)
console
0x414bf389000000000000000000000000c5e7703d4647ff77bc733bb56d120471b83382e2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006507f7280000000000000000000000000000000000000000000000000001d6c3ef643800000000000000000000000000000000000000000000000000014fcd4e1e5ce1300000000000000000000000000000000000000000000000000000000000000000
,
0x49404b7c000000000000000000000000000000000000000000000000014fcd4e1e5ce13000000000000000000000000019edc2f769ac416c725e1c4032be50c1d4b3bd3a
Java 解码
package com.hlf;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import net.osslabz.evm.abi.decoder.AbiDecoder;
import net.osslabz.evm.abi.decoder.DecodedFunctionCall;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.*;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Numeric;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName: DecodeV3Test
* @Author: lfhuang
* @CreateDate: 2023/9/18 3:13 PM
* @Description:
* @Version: 1.0
**/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class DecodeV3Test {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException {
// 解析uniswap v3的multicall(bytes[] data)函数
// https://github.com/Uniswap/v3-periphery/blob/v1.0.0/contracts/base/Multicall.sol
// https://etherscan.io/tx/0xecb398ee0e00ec3b3f1bc4d3d34c69153c2abeef995d39a69c1f30300330c18e
// 原input数据
String callData = "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000104414bf389000000000000000000000000c5e7703d4647ff77bc733bb56d120471b83382e2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006507f7280000000000000000000000000000000000000000000000000001d6c3ef643800000000000000000000000000000000000000000000000000014fcd4e1e5ce130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004449404b7c000000000000000000000000000000000000000000000000014fcd4e1e5ce13000000000000000000000000019edc2f769ac416c725e1c4032be50c1d4b3bd3a00000000000000000000000000000000000000000000000000000000";
/**
* 解析后的数据1 exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))
* 0x414bf389000000000000000000000000c5e7703d4647ff77bc733bb56d120471b83382e2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006507f7280000000000000000000000000000000000000000000000000001d6c3ef643800000000000000000000000000000000000000000000000000014fcd4e1e5ce1300000000000000000000000000000000000000000000000000000000000000000
* 414bf389
* 000000000000000000000000c5e7703d4647ff77bc733bb56d120471b83382e2
* 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
* 0000000000000000000000000000000000000000000000000000000000000bb8
* 0000000000000000000000000000000000000000000000000000000000000000
* 000000000000000000000000000000000000000000000000000000006507f728
* 0000000000000000000000000000000000000000000000000001d6c3ef643800
* 000000000000000000000000000000000000000000000000014fcd4e1e5ce130
* 0000000000000000000000000000000000000000000000000000000000000000
* 解析后的数据2 unwrapWETH9(uint256, address)
* 0x49404b7c000000000000000000000000000000000000000000000000014fcd4e1e5ce13000000000000000000000000019edc2f769ac416c725e1c4032be50c1d4b3bd3a
* 49404b7c
* 000000000000000000000000000000000000000000000000014fcd4e1e5ce130
* 00000000000000000000000019edc2f769ac416c725e1c4032be50c1d4b3bd3a
*/
List list = new ArrayList();
int index = 64;//32字节
int length = callData.length() / index;
int beginIndex = 0;
int endIndex = 64;
for (int i = 0; i < length; i++) {
list.add(Numeric.hexStringToByteArray(callData.substring(beginIndex, endIndex)));
beginIndex = beginIndex + index;
endIndex = endIndex + index;
}
Function function = new Function("multicall", Arrays.<Type>asList(new DynamicArray<DynamicBytes>(DynamicBytes.class, org.web3j.abi.Utils.typeMap(list, DynamicBytes.class))), Arrays.<TypeReference<?>>asList(new TypeReference<DynamicArray<DynamicBytes>>() {
}));
System.out.println("encoded:" + FunctionEncoder.encode(function));
List<Type> decode = FunctionReturnDecoder.decode(callData, function.getOutputParameters());
List<DynamicBytes> decodeList = (List<DynamicBytes>) decode.get(0).getValue();
String currentDirectory = System.getProperty("user.dir");
AbiDecoder abiDecoder = new AbiDecoder(currentDirectory + "/robot-monitor/abi/SwapV3Router.json");
for (DynamicBytes dynamicBytes1 : decodeList) {
String data = Numeric.toHexString(dynamicBytes1.getValue());
System.out.println("decode:" + data);
DecodedFunctionCall decodedFunctionCall1 = abiDecoder.decodeFunctionCall(data);
System.out.println("解析对应abi数据:" + JSON.toJSONString(decodedFunctionCall1));
}
}
}
console
encoded:0xac9650d8000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001040000000000000000000000000000000000000000000000000000000000000020414bf389000000000000000000000000c5e7703d4647ff77bc733bb56d1204710000000000000000000000000000000000000000000000000000000000000020b83382e2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead90800000000000000000000000000000000000000000000000000000000000000203c756cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000bb8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000206507f7280000000000000000000000000000000000000000000000000001d6c30000000000000000000000000000000000000000000000000000000000000020ef643800000000000000000000000000000000000000000000000000014fcd4e00000000000000000000000000000000000000000000000000000000000000201e5ce130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000002049404b7c000000000000000000000000000000000000000000000000014fcd4e00000000000000000000000000000000000000000000000000000000000000201e5ce13000000000000000000000000019edc2f769ac416c725e1c4032be50c10000000000000000000000000000000000000000000000000000000000000020d4b3bd3a00000000000000000000000000000000000000000000000000000000
decode:0x414bf389000000000000000000000000c5e7703d4647ff77bc733bb56d120471b83382e2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006507f7280000000000000000000000000000000000000000000000000001d6c3ef643800000000000000000000000000000000000000000000000000014fcd4e1e5ce1300000000000000000000000000000000000000000000000000000000000000000
解析对应abi数据:{"name":"exactInputSingle","paramList":[{"name":"params","type":"tuple","value":["0xc5e7703d4647ff77bc733bb56d120471b83382e2","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",3000,"0x0000000000000000000000000000000000000000",1695020840,517612000000000,94519852598616368,0]}],"params":[{"$ref":"$.paramList[0]"}],"size":1}
decode:0x49404b7c000000000000000000000000000000000000000000000000014fcd4e1e5ce13000000000000000000000000019edc2f769ac416c725e1c4032be50c1d4b3bd3a
解析对应abi数据:{"name":"unwrapWETH9","paramList":[{"name":"amountMinimum","type":"uint256","value":94519852598616368},{"name":"recipient","type":"address","value":"0x19edc2f769ac416c725e1c4032be50c1d4b3bd3a"}],"params":[{"$ref":"$.paramList[0]"},{"$ref":"$.paramList[1]"}],"size":2}