Skip to content

Commit

Permalink
Merge pull request #2124 from SergioIOB/feature/fixDuplicatedEventNames
Browse files Browse the repository at this point in the history
Counter on duplicated event names
  • Loading branch information
gtebrean authored Dec 17, 2024
2 parents 6e553a5 + 95e9034 commit bc6eda5
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -418,10 +418,22 @@ FieldSpec createBinaryDefinition(String binary) {
.build();
}

private FieldSpec createEventDefinition(String name, List<NamedTypeName> parameters) {
private FieldSpec createEventDefinition(
String name,
List<NamedTypeName> parameters,
Map<String, Integer> eventsCount,
AbiDefinition event
) {

CodeBlock initializer = buildVariableLengthEventInitializer(name, parameters);

Integer occurrences = eventsCount.get(name);
if (occurrences > 1) {
event.setName(name + (occurrences - 1));
eventsCount.replace(name, occurrences - 1);
name = event.getName();
}

return FieldSpec.builder(Event.class, buildEventDefinitionName(name))
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer(initializer)
Expand All @@ -432,26 +444,50 @@ private String buildEventDefinitionName(String eventName) {
return eventName.toUpperCase() + "_EVENT";
}

private List<MethodSpec> buildFunctionDefinitions(
List<MethodSpec> buildFunctionDefinitions(
String className,
TypeSpec.Builder classBuilder,
List<AbiDefinition> functionDefinitions)
throws ClassNotFoundException {

Set<String> duplicateFunctionNames = getDuplicateFunctionNames(functionDefinitions);
Map<String, Integer> eventsCount = getDuplicatedEventNames(functionDefinitions);
List<MethodSpec> methodSpecs = new ArrayList<>();
for (AbiDefinition functionDefinition : functionDefinitions) {
if (functionDefinition.getType().equals(TYPE_FUNCTION)) {
String functionName = funcNameToConst(functionDefinition.getName(), true);
boolean useUpperCase = !duplicateFunctionNames.contains(functionName);
methodSpecs.addAll(buildFunctions(functionDefinition, useUpperCase));
} else if (functionDefinition.getType().equals(TYPE_EVENT)) {
methodSpecs.addAll(buildEventFunctions(functionDefinition, classBuilder));
methodSpecs.addAll(
buildEventFunctions(functionDefinition, classBuilder, eventsCount)
);
}
}
return methodSpecs;
}

Map<String, Integer> getDuplicatedEventNames(List<AbiDefinition> functionDefinitions) {
Map<String, Integer> countMap = new HashMap<>();

functionDefinitions.stream()
.filter(
function ->
TYPE_EVENT.equals(function.getType()) && function.getName() != null)
.forEach(
function -> {
String functionName = function.getName();
if (countMap.containsKey(functionName)) {
int count = countMap.get(functionName);
countMap.put(functionName, count + 1);
} else {
countMap.put(functionName, 1);
}
});

return countMap;
}

private List<TypeSpec> buildStructTypes(final List<AbiDefinition> functionDefinitions)
throws ClassNotFoundException {
final List<AbiDefinition.NamedType> orderedKeys = extractStructs(functionDefinitions);
Expand Down Expand Up @@ -1917,11 +1953,12 @@ private static String getEventFromLogFunctionName(String functionName) {
}

List<MethodSpec> buildEventFunctions(
AbiDefinition functionDefinition, TypeSpec.Builder classBuilder)
AbiDefinition functionDefinition,
TypeSpec.Builder classBuilder,
Map<String, Integer> eventsCount
)
throws ClassNotFoundException {
String functionName = functionDefinition.getName();
List<AbiDefinition.NamedType> inputs = functionDefinition.getInputs();
String responseClassName = Strings.capitaliseFirstLetter(functionName) + "EventResponse";

List<NamedTypeName> parameters = new ArrayList<>();
List<NamedTypeName> indexedParameters = new ArrayList<>();
Expand All @@ -1946,7 +1983,15 @@ List<MethodSpec> buildEventFunctions(
parameters.add(parameter);
}

classBuilder.addField(createEventDefinition(functionName, parameters));
String functionName = functionDefinition.getName();

classBuilder.addField(createEventDefinition(
functionName, parameters, eventsCount, functionDefinition
));

functionName = functionDefinition.getName();

String responseClassName = Strings.capitaliseFirstLetter(functionName) + "EventResponse";

classBuilder.addType(
buildEventResponseObject(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,11 @@ public void testBuildEventConstantMultipleValueReturn() throws Exception {
TypeSpec.Builder builder = TypeSpec.classBuilder("testClass");

builder.addMethods(
solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder));
solidityFunctionWrapper.buildEventFunctions(
functionDefinition,
builder,
solidityFunctionWrapper.getDuplicatedEventNames(
Collections.singletonList(functionDefinition))));

String expected =
"class testClass {\n"
Expand Down Expand Up @@ -773,7 +777,11 @@ public void testBuildEventWithNamedAndNoNamedParameters() throws Exception {
TypeSpec.Builder builder = TypeSpec.classBuilder("testClass");

builder.addMethods(
solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder));
solidityFunctionWrapper.buildEventFunctions(
functionDefinition,
builder,
solidityFunctionWrapper.getDuplicatedEventNames(
Collections.singletonList(functionDefinition))));

String expected =
"class testClass {\n"
Expand Down Expand Up @@ -853,7 +861,11 @@ public void testBuildEventWithNativeList() throws Exception {
TypeSpec.Builder builder = TypeSpec.classBuilder("testClass");

builder.addMethods(
solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder));
solidityFunctionWrapper.buildEventFunctions(
functionDefinition,
builder,
solidityFunctionWrapper.getDuplicatedEventNames(
Collections.singletonList(functionDefinition))));

String expected =
"class testClass {\n"
Expand Down Expand Up @@ -926,6 +938,140 @@ public void testBuildFuncNameConstants() throws Exception {
assertEquals(builder.build().toString(), (expected));
}

@Test
public void testBuildFunctionDuplicatedEventNames() throws Exception {
AbiDefinition firstEventDefinition =
new AbiDefinition(
false,
Arrays.asList(
new NamedType("action", "string", false),
new NamedType("pauseState", "bool", false)),
"eventName",
Collections.emptyList(),
"event",
false);
AbiDefinition secondEventDefinition =
new AbiDefinition(
false,
Arrays.asList(
new NamedType("cToken", "address", false),
new NamedType("action", "string", false),
new NamedType("pauseState", "bool", false)),
"eventName",
Collections.emptyList(),
"event",
false);
TypeSpec.Builder builder = TypeSpec.classBuilder("testClass");
builder.addMethods(
solidityFunctionWrapper.buildFunctionDefinitions(
"testClass",
builder,
Arrays.asList(firstEventDefinition, secondEventDefinition)));

String expected =
"class testClass {\n" +
" public static final org.web3j.abi.datatypes.Event EVENTNAME1_EVENT = new org.web3j.abi.datatypes.Event(\"eventName\", \n" +
" java.util.Arrays.<org.web3j.abi.TypeReference<?>>asList(new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.Utf8String>() {}, new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.Bool>() {}));\n" +
" ;\n" +
"\n" +
" public static final org.web3j.abi.datatypes.Event EVENTNAME_EVENT = new org.web3j.abi.datatypes.Event(\"eventName\", \n" +
" java.util.Arrays.<org.web3j.abi.TypeReference<?>>asList(new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.Address>() {}, new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.Utf8String>() {}, new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.Bool>() {}));\n" +
" ;\n" +
"\n" +
" public static java.util.List<EventName1EventResponse> getEventName1Events(\n" +
" org.web3j.protocol.core.methods.response.TransactionReceipt transactionReceipt) {\n" +
" java.util.List<org.web3j.tx.Contract.EventValuesWithLog> valueList = staticExtractEventParametersWithLog(EVENTNAME1_EVENT, transactionReceipt);\n" +
" java.util.ArrayList<EventName1EventResponse> responses = new java.util.ArrayList<EventName1EventResponse>(valueList.size());\n" +
" for (org.web3j.tx.Contract.EventValuesWithLog eventValues : valueList) {\n" +
" EventName1EventResponse typedResponse = new EventName1EventResponse();\n" +
" typedResponse.log = eventValues.getLog();\n" +
" typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" +
" typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(1).getValue();\n" +
" responses.add(typedResponse);\n" +
" }\n" +
" return responses;\n" +
" }\n" +
"\n" +
" public static EventName1EventResponse getEventName1EventFromLog(\n" +
" org.web3j.protocol.core.methods.response.Log log) {\n" +
" org.web3j.tx.Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(EVENTNAME1_EVENT, log);\n" +
" EventName1EventResponse typedResponse = new EventName1EventResponse();\n" +
" typedResponse.log = log;\n" +
" typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" +
" typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(1).getValue();\n" +
" return typedResponse;\n" +
" }\n" +
"\n" +
" public io.reactivex.Flowable<EventName1EventResponse> eventName1EventFlowable(\n" +
" org.web3j.protocol.core.methods.request.EthFilter filter) {\n" +
" return web3j.ethLogFlowable(filter).map(log -> getEventName1EventFromLog(log));\n" +
" }\n" +
"\n" +
" public io.reactivex.Flowable<EventName1EventResponse> eventName1EventFlowable(\n" +
" org.web3j.protocol.core.DefaultBlockParameter startBlock,\n" +
" org.web3j.protocol.core.DefaultBlockParameter endBlock) {\n" +
" org.web3j.protocol.core.methods.request.EthFilter filter = new org.web3j.protocol.core.methods.request.EthFilter(startBlock, endBlock, getContractAddress());\n" +
" filter.addSingleTopic(org.web3j.abi.EventEncoder.encode(EVENTNAME1_EVENT));\n" +
" return eventName1EventFlowable(filter);\n" +
" }\n" +
"\n" +
" public static java.util.List<EventNameEventResponse> getEventNameEvents(\n" +
" org.web3j.protocol.core.methods.response.TransactionReceipt transactionReceipt) {\n" +
" java.util.List<org.web3j.tx.Contract.EventValuesWithLog> valueList = staticExtractEventParametersWithLog(EVENTNAME_EVENT, transactionReceipt);\n" +
" java.util.ArrayList<EventNameEventResponse> responses = new java.util.ArrayList<EventNameEventResponse>(valueList.size());\n" +
" for (org.web3j.tx.Contract.EventValuesWithLog eventValues : valueList) {\n" +
" EventNameEventResponse typedResponse = new EventNameEventResponse();\n" +
" typedResponse.log = eventValues.getLog();\n" +
" typedResponse.cToken = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" +
" typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(1).getValue();\n" +
" typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(2).getValue();\n" +
" responses.add(typedResponse);\n" +
" }\n" +
" return responses;\n" +
" }\n" +
"\n" +
" public static EventNameEventResponse getEventNameEventFromLog(\n" +
" org.web3j.protocol.core.methods.response.Log log) {\n" +
" org.web3j.tx.Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(EVENTNAME_EVENT, log);\n" +
" EventNameEventResponse typedResponse = new EventNameEventResponse();\n" +
" typedResponse.log = log;\n" +
" typedResponse.cToken = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" +
" typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(1).getValue();\n" +
" typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(2).getValue();\n" +
" return typedResponse;\n" +
" }\n" +
"\n" +
" public io.reactivex.Flowable<EventNameEventResponse> eventNameEventFlowable(\n" +
" org.web3j.protocol.core.methods.request.EthFilter filter) {\n" +
" return web3j.ethLogFlowable(filter).map(log -> getEventNameEventFromLog(log));\n" +
" }\n" +
"\n" +
" public io.reactivex.Flowable<EventNameEventResponse> eventNameEventFlowable(\n" +
" org.web3j.protocol.core.DefaultBlockParameter startBlock,\n" +
" org.web3j.protocol.core.DefaultBlockParameter endBlock) {\n" +
" org.web3j.protocol.core.methods.request.EthFilter filter = new org.web3j.protocol.core.methods.request.EthFilter(startBlock, endBlock, getContractAddress());\n" +
" filter.addSingleTopic(org.web3j.abi.EventEncoder.encode(EVENTNAME_EVENT));\n" +
" return eventNameEventFlowable(filter);\n" +
" }\n" +
"\n" +
" public static class EventName1EventResponse extends org.web3j.protocol.core.methods.response.BaseEventResponse {\n" +
" public java.lang.String action;\n" +
"\n" +
" public java.lang.Boolean pauseState;\n" +
" }\n" +
"\n" +
" public static class EventNameEventResponse extends org.web3j.protocol.core.methods.response.BaseEventResponse {\n" +
" public java.lang.String cToken;\n" +
"\n" +
" public java.lang.String action;\n" +
"\n" +
" public java.lang.Boolean pauseState;\n" +
" }\n" +
"}\n";

assertEquals(builder.build().toString(), (expected));
}

@Test
public void testBuildFunctionTransactionAndCall() throws Exception {
AbiDefinition functionDefinition =
Expand Down

0 comments on commit bc6eda5

Please sign in to comment.