
Subscribe to liubo

Subscribe to liubo
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers
最近在做 nft 相关的小项目,需要通过解析一些 eth log 来触发后台的相关逻辑。看了下 web3j 发现有两种方式可以实现这个解析。
编译 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);});
如果你跟我一样,需要监控多个合约,多种 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 解析这个日志数据,我们可以先定义好对应的 Event
public 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,则需要先统一解析出来,再依次解析。
最近在做 nft 相关的小项目,需要通过解析一些 eth log 来触发后台的相关逻辑。看了下 web3j 发现有两种方式可以实现这个解析。
编译 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);});
如果你跟我一样,需要监控多个合约,多种 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 解析这个日志数据,我们可以先定义好对应的 Event
public 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,则需要先统一解析出来,再依次解析。
No activity yet