# Web3j 读取 eth log **Published by:** [liubo](https://paragraph.com/@liubo/) **Published on:** 2022-07-05 **URL:** https://paragraph.com/@liubo/web3j-eth-log ## Content 最近在做 nft 相关的小项目,需要通过解析一些 eth log 来触发后台的相关逻辑。看了下 web3j 发现有两种方式可以实现这个解析。1、直接利用 web3j 生成 wrapper code编译 solidity 代码 solc <contract>.sol --bin --abi --optimize -o <output-dir>/ solc contract.sol --bin --abi --optimize -o build/ --include-path ./node_modules --base-path ./ 生成 wrapper code web3j generate solidity -b /path/to/<smart-contract>.bin -a /path/to/<smart-contract>.abi -o /path/to/src/main/java -p com.your.organisation.name 生成的代码里有直接相关的 event 订阅和查询方法,可以直接使用。这里也直接会把相关的日志数据解析成对应的 xxEventResponse,可以直接使用。new Contract(contractAddress,web3j).xxxEventFlowable(filter).subscribe(x->{process(x);}); 2、手动订阅解析如果你跟我一样,需要监控多个合约,多种 event,那就可以自己定制 filter 进行订阅。 List<String> contracts = Lists.newArrayList(contractAddressOne, contractAddressTwo); EthFilter filter = new EthFilter( DefaultBlockParameter.valueOf(startNumber), DefaultBlockParameterName.LATEST, contracts); web3j .ethLogFlowable(filter) .doOnError( ex -> { log.error("log trace failed", ex); }) .subscribe( eventLog -> { process(eventLog); }); } 跟第一种方式不一样,这里拿到的 event 数据都比较原始,需要我们手动来进行解析。 event log 里的数据分为两类,一种是 topic,一种是 data。 topic 对应 solidity 中 indexed 的值,data 则对应未 indexed 的值。 举个例子,以下这个 event 定义里的 operator 就属于 topic; itemIds 和 tokenIds 则属于 data。 另外,topic[0] 是函数签名,所以取数据的时候是从下标 1 开始。event Mint(address indexed operator, uint64[] itemIds, uint256 [] tokenIds); 使用 web3j 解析这个日志数据,我们可以先定义好对应的 Eventpublic static final Event MINT = new Event( "Mint", Arrays.asList( new TypeReference<Address>(true) {}, new TypeReference<DynamicArray<Uint64>>() {}, new TypeReference<DynamicArray<Uint256>>() {})); 然后将对应的 log 数据转换一下public void convert(Log eventLog) { Address address = (Address) FunctionReturnDecoder.decodeIndexedValue( eventLog.getTopics().get(1), new TypeReference<Address>() {}); List<Type> params = FunctionReturnDecoder.decode( eventLog.getData(), EthEvent.MINT.getNonIndexedParameters()); List<Long> itemIds = ((DynamicArray<Uint64>) params.get(0)) .getValue().stream().map(x -> x.getValue().longValue()).collect(Collectors.toList()); List<String> tokens = ((DynamicArray<Uint256>) params.get(1)) .getValue().stream() .map(x -> Numeric.toHexStringWithPrefix(x.getValue())) .collect(Collectors.toList()); } 这里需要注意的就是,对于 topic,我们可以通过下标一个个解析。而对于 data,则需要先统一解析出来,再依次解析。 ## Publication Information - [liubo](https://paragraph.com/@liubo/): Publication homepage - [All Posts](https://paragraph.com/@liubo/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@liubo): Subscribe to updates