Skip to content

Commit 1e79b15

Browse files
committed
Merge branch 'upstream/main' into fix/struct-decode-final
2 parents 457da59 + 1fc8a1d commit 1e79b15

18 files changed

Lines changed: 755 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
88
### Bug Fixes
99

1010
- Fix dynamic array decoding in generated wrappers for struct types [#2272](https://github.com/LFDT-web3j/web3j/pull/2272)
11+
- Fix incorrect casting for array types in generated contract wrappers [#2274](https://github.com/LFDT-web3j/web3j/pull/2274)
1112
- Fix NullPointerException when deriving child keys from public-only Bip32ECKeyPair [#2284](https://github.com/LFDT-web3j/web3j/pull/2284)
1213
- Fix Utf8String encoding + dynamic array for non-ASCII characters [#2289](https://github.com/LFDT-web3j/web3j/pull/2289)
1314
- Fix pass accessList to parent in Transaction7702 constructor [#2292](https://github.com/LFDT-web3j/web3j/pull/2292)
@@ -25,6 +26,8 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
2526
- Add `eth_blobBaseFee` RPC (EIP-7918 / Fusaka-correct blob base fee) [#2300](https://github.com/LFDT-web3j/web3j/pull/2300)
2627
- Adds context7 json file [#2301](https://github.com/LFDT-web3j/web3j/pull/2301)
2728
- Bump snapshot version to 6.0.0 [#2302](https://github.com/LFDT-web3j/web3j/pull/2302)
29+
- Add support for txpool_contentFrom JSON-RPC method to query transaction pool by address [#2262](https://github.com/LFDT-web3j/web3j/pull/2262)
30+
- Add support for txpool_inspect JSON-RPC method [#2262](https://github.com/LFDT-web3j/web3j/pull/2262)
2831

2932
### BREAKING CHANGES
3033

codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,9 @@ TypeSpec buildEventResponseObject(
19621962
for (org.web3j.codegen.SolidityFunctionWrapper.NamedTypeName namedType :
19631963
indexedParameters) {
19641964
final TypeName typeName;
1965-
if (namedType.getType().equals("tuple")) {
1965+
if (isHashedIndexedType(namedType.getType())) {
1966+
typeName = useNativeJavaTypes ? TypeName.get(byte[].class) : ClassName.get("org.web3j.abi.datatypes.generated", "Bytes32");
1967+
} else if (namedType.getType().equals("tuple")) {
19661968
typeName = structClassNameMap.get(namedType.structIdentifier());
19671969
} else if (namedType.getType().startsWith("tuple")
19681970
&& namedType.getType().contains("[")) {
@@ -2191,48 +2193,37 @@ CodeBlock buildTypedResponse(
21912193
for (int i = 0; i < indexedParameters.size(); i++) {
21922194
final NamedTypeName namedTypeName = indexedParameters.get(i);
21932195
final String nativeConversion;
2194-
boolean needsArrayCast = false;
2195-
if (useNativeJavaTypes
2196-
&& structClassNameMap.values().stream()
2196+
if (useNativeJavaTypes) {
2197+
if (isHashedIndexedType(namedTypeName.getType())) {
2198+
nativeConversion = ".getValue()";
2199+
} else if (structClassNameMap.values().stream()
21972200
.map(ClassName::simpleName)
21982201
.noneMatch(
21992202
name -> name.equals(namedTypeName.getTypeName().toString()))) {
2200-
if (namedTypeName.typeName instanceof ParameterizedTypeName
2201-
&& isNotArrayOfStructs(namedTypeName)) {
2202-
nativeConversion = ".getNativeValueCopy()";
2203-
needsArrayCast = true;
2204-
} else {
22052203
nativeConversion = ".getValue()";
2204+
} else {
2205+
nativeConversion = "";
22062206
}
22072207
} else {
22082208
nativeConversion = "";
22092209
}
22102210
final TypeName indexedEventWrapperType;
2211-
if (namedTypeName.getType().equals("tuple")) {
2211+
if (isHashedIndexedType(namedTypeName.getType())) {
2212+
indexedEventWrapperType = useNativeJavaTypes ? TypeName.get(byte[].class) : ClassName.get("org.web3j.abi.datatypes.generated", "Bytes32");
2213+
} else if (namedTypeName.getType().equals("tuple")) {
22122214
indexedEventWrapperType = structClassNameMap.get(namedTypeName.structIdentifier());
22132215
} else if (namedTypeName.getType().startsWith("tuple")
22142216
&& namedTypeName.getType().contains("[")) {
22152217
indexedEventWrapperType = buildStructArrayTypeName(namedTypeName.namedType, true);
22162218
} else {
22172219
indexedEventWrapperType = getIndexedEventWrapperType(namedTypeName.getTypeName());
22182220
}
2219-
if (needsArrayCast) {
2220-
builder.addStatement(
2221-
"$L.$L = ($T) (($T) eventValues.getIndexedValues().get($L))"
2222-
+ nativeConversion,
2223-
objectName,
2224-
createValidParamName(namedTypeName.getName(), i),
2225-
indexedEventWrapperType,
2226-
Array.class,
2227-
i);
2228-
} else {
2229-
builder.addStatement(
2230-
"$L.$L = ($T) eventValues.getIndexedValues().get($L)" + nativeConversion,
2231-
objectName,
2232-
createValidParamName(namedTypeName.getName(), i),
2233-
indexedEventWrapperType,
2234-
i);
2235-
}
2221+
builder.addStatement(
2222+
"$L.$L = ($T) eventValues.getIndexedValues().get($L)" + nativeConversion,
2223+
objectName,
2224+
createValidParamName(namedTypeName.getName(), i),
2225+
indexedEventWrapperType,
2226+
i);
22362227
}
22372228

22382229
for (int i = 0; i < nonIndexedParameters.size(); i++) {
@@ -2486,6 +2477,14 @@ private static String funcNameToConst(String funcName, boolean useUpperCase) {
24862477
}
24872478
}
24882479

2480+
private static boolean isHashedIndexedType(String solidityType) {
2481+
return solidityType.contains("[")
2482+
|| solidityType.equals("string")
2483+
|| solidityType.equals("bytes")
2484+
|| solidityType.equals("tuple")
2485+
|| solidityType.startsWith("tuple");
2486+
}
2487+
24892488
private static class NamedTypeName {
24902489
private final TypeName typeName;
24912490
private final AbiDefinition.NamedType namedType;

codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,6 @@ private void compareJavaFile(String inputFileName, boolean useBin, boolean abiFu
298298
"java",
299299
inputFileName + ".java"),
300300
File.separator));
301-
System.out.println("EXPECTED: " + fileExpected.getAbsolutePath());
302-
System.out.println("ACTUAL: " + fileActual.getAbsolutePath());
303301
assertEquals(
304302
new String(Files.readAllBytes(fileExpected.toPath())).replaceAll("(\r\n|\n)", ""),
305303
new String(Files.readAllBytes(fileActual.toPath())).replaceAll("(\r\n|\n)", ""));

codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,36 @@ public void testGetEventNativeTypeParameterized() {
173173
(TypeName.get(byte[].class)));
174174
}
175175

176+
@Test
177+
public void testGetEventNativeTypeBytes32Array() {
178+
// bytes32[] maps to byte[] representing the Keccak-256 hash
179+
assertEquals(
180+
getEventNativeType(
181+
ParameterizedTypeName.get(
182+
ClassName.get(DynamicArray.class), TypeName.get(Bytes32.class))),
183+
(TypeName.get(byte[].class)));
184+
}
185+
186+
@Test
187+
public void testBuildEventWithIndexedArray() throws Exception {
188+
NamedType array = new NamedType("array", "uint256[]", true); // indexed = true
189+
190+
AbiDefinition functionDefinition =
191+
new AbiDefinition(
192+
false, Arrays.asList(array), "Transfer", new ArrayList<>(), "event", false);
193+
TypeSpec.Builder builder = TypeSpec.classBuilder("TestClass");
194+
195+
builder.addMethods(
196+
solidityFunctionWrapper.buildEventFunctions(
197+
functionDefinition,
198+
builder,
199+
solidityFunctionWrapper.getDuplicatedEventNames(
200+
Collections.singletonList(functionDefinition))));
201+
202+
String expected = loadExpected("TestBuildEventWithIndexedArray.java");
203+
assertEquals(expected, builder.build().toString());
204+
}
205+
176206
@Test
177207
public void testBuildFunctionTransaction() throws Exception {
178208
AbiDefinition functionDefinition =
@@ -1260,4 +1290,102 @@ public void testBuildCustomErrorDefinitionsWithDuplicateNames() throws Exception
12601290

12611291
assertEquals(expectedJavaCode, builder.build().toString());
12621292
}
1293+
1294+
@Test
1295+
public void testBuildEventWithIndexedStaticArray() throws Exception {
1296+
NamedType array = new NamedType("array", "bytes32[2]", true);
1297+
1298+
AbiDefinition functionDefinition =
1299+
new AbiDefinition(
1300+
false, Arrays.asList(array), "Transfer", new ArrayList<>(), "event", false);
1301+
TypeSpec.Builder builder = TypeSpec.classBuilder("TestClass");
1302+
1303+
builder.addMethods(
1304+
solidityFunctionWrapper.buildEventFunctions(
1305+
functionDefinition,
1306+
builder,
1307+
solidityFunctionWrapper.getDuplicatedEventNames(
1308+
Collections.singletonList(functionDefinition))));
1309+
1310+
String expected = loadExpected("TestBuildEventWithIndexedStaticArray.java");
1311+
assertEquals(expected, builder.build().toString());
1312+
}
1313+
1314+
@Test
1315+
public void testBuildEventWithIndexedNestedArray() throws Exception {
1316+
NamedType array = new NamedType("array", "uint256[][]", true);
1317+
1318+
AbiDefinition functionDefinition =
1319+
new AbiDefinition(
1320+
false, Arrays.asList(array), "Transfer", new ArrayList<>(), "event", false);
1321+
TypeSpec.Builder builder = TypeSpec.classBuilder("TestClass");
1322+
1323+
builder.addMethods(
1324+
solidityFunctionWrapper.buildEventFunctions(
1325+
functionDefinition,
1326+
builder,
1327+
solidityFunctionWrapper.getDuplicatedEventNames(
1328+
Collections.singletonList(functionDefinition))));
1329+
1330+
String expected = loadExpected("TestBuildEventWithIndexedNestedArray.java");
1331+
assertEquals(expected, builder.build().toString());
1332+
}
1333+
1334+
@Test
1335+
public void testBuildEventWithIndexedArrayWithoutNativeTypes() throws Exception {
1336+
SolidityFunctionWrapper nonNativeWrapper =
1337+
new SolidityFunctionWrapper(
1338+
false, false, false, Address.DEFAULT_LENGTH, generationReporter);
1339+
1340+
NamedType array = new NamedType("array", "uint256[]", true);
1341+
1342+
AbiDefinition functionDefinition =
1343+
new AbiDefinition(
1344+
false, Arrays.asList(array), "Transfer", new ArrayList<>(), "event", false);
1345+
TypeSpec.Builder builder = TypeSpec.classBuilder("TestClass");
1346+
1347+
builder.addMethods(
1348+
nonNativeWrapper.buildEventFunctions(
1349+
functionDefinition,
1350+
builder,
1351+
nonNativeWrapper.getDuplicatedEventNames(
1352+
Collections.singletonList(functionDefinition))));
1353+
1354+
String expected = loadExpected("TestBuildEventWithIndexedArrayWithoutNativeTypes.java");
1355+
assertEquals(expected, builder.build().toString());
1356+
}
1357+
1358+
@Test
1359+
public void testBuildEventWithIndexedStruct() throws Exception {
1360+
java.lang.reflect.Field mapField = SolidityFunctionWrapper.class.getDeclaredField("structClassNameMap");
1361+
mapField.setAccessible(true);
1362+
java.util.Map<String, ClassName> map =
1363+
(java.util.Map<String, ClassName>) mapField.get(solidityFunctionWrapper);
1364+
map.put("struct MyContract.SomeStruct", ClassName.get("", "SomeStruct"));
1365+
1366+
NamedType struct = new NamedType("myStruct", "tuple", new ArrayList<>(), "struct MyContract.SomeStruct", true);
1367+
1368+
AbiDefinition functionDefinition =
1369+
new AbiDefinition(
1370+
false, Arrays.asList(struct), "Transfer", new ArrayList<>(), "event", false);
1371+
TypeSpec.Builder builder = TypeSpec.classBuilder("TestClass");
1372+
1373+
builder.addMethods(
1374+
solidityFunctionWrapper.buildEventFunctions(
1375+
functionDefinition,
1376+
builder,
1377+
solidityFunctionWrapper.getDuplicatedEventNames(
1378+
Collections.singletonList(functionDefinition))));
1379+
1380+
String expected = loadExpected("TestBuildEventWithIndexedStruct.java");
1381+
assertEquals(expected, builder.build().toString());
1382+
}
1383+
1384+
private String loadExpected(String filename) throws Exception {
1385+
java.net.URL url = getClass().getResource("/expected/" + filename);
1386+
if (url == null) {
1387+
throw new java.io.FileNotFoundException("Resource not found: /expected/" + filename);
1388+
}
1389+
return new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(url.toURI()))).replace("\r\n", "\n");
1390+
}
12631391
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
class TestClass {
2+
public static final org.web3j.abi.datatypes.Event TRANSFER_EVENT = new org.web3j.abi.datatypes.Event("Transfer",
3+
java.util.Arrays.<org.web3j.abi.TypeReference<?>>asList(new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.generated.Uint256>>(true) {}));
4+
;
5+
6+
public static java.util.List<TransferEventResponse> getTransferEvents(
7+
org.web3j.protocol.core.methods.response.TransactionReceipt transactionReceipt) {
8+
java.util.List<org.web3j.tx.Contract.EventValuesWithLog> valueList = staticExtractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt);
9+
java.util.ArrayList<TransferEventResponse> responses = new java.util.ArrayList<TransferEventResponse>(valueList.size());
10+
for (org.web3j.tx.Contract.EventValuesWithLog eventValues : valueList) {
11+
TransferEventResponse typedResponse = new TransferEventResponse();
12+
typedResponse.log = eventValues.getLog();
13+
typedResponse.array = (byte[]) eventValues.getIndexedValues().get(0).getValue();
14+
responses.add(typedResponse);
15+
}
16+
return responses;
17+
}
18+
19+
public static TransferEventResponse getTransferEventFromLog(
20+
org.web3j.protocol.core.methods.response.Log log) {
21+
org.web3j.tx.Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSFER_EVENT, log);
22+
TransferEventResponse typedResponse = new TransferEventResponse();
23+
typedResponse.log = log;
24+
typedResponse.array = (byte[]) eventValues.getIndexedValues().get(0).getValue();
25+
return typedResponse;
26+
}
27+
28+
public io.reactivex.Flowable<TransferEventResponse> transferEventFlowable(
29+
org.web3j.protocol.core.methods.request.EthFilter filter) {
30+
return web3j.ethLogFlowable(filter).map(log -> getTransferEventFromLog(log));
31+
}
32+
33+
public io.reactivex.Flowable<TransferEventResponse> transferEventFlowable(
34+
org.web3j.protocol.core.DefaultBlockParameter startBlock,
35+
org.web3j.protocol.core.DefaultBlockParameter endBlock) {
36+
org.web3j.protocol.core.methods.request.EthFilter filter = new org.web3j.protocol.core.methods.request.EthFilter(startBlock, endBlock, getContractAddress());
37+
filter.addSingleTopic(org.web3j.abi.EventEncoder.encode(TRANSFER_EVENT));
38+
return transferEventFlowable(filter);
39+
}
40+
41+
public static class TransferEventResponse extends org.web3j.protocol.core.methods.response.BaseEventResponse {
42+
public byte[] array;
43+
}
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
class TestClass {
2+
public static final org.web3j.abi.datatypes.Event TRANSFER_EVENT = new org.web3j.abi.datatypes.Event("Transfer",
3+
java.util.Arrays.<org.web3j.abi.TypeReference<?>>asList(new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.generated.Uint256>>(true) {}));
4+
;
5+
6+
public static java.util.List<TransferEventResponse> getTransferEvents(
7+
org.web3j.protocol.core.methods.response.TransactionReceipt transactionReceipt) {
8+
java.util.List<org.web3j.tx.Contract.EventValuesWithLog> valueList = staticExtractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt);
9+
java.util.ArrayList<TransferEventResponse> responses = new java.util.ArrayList<TransferEventResponse>(valueList.size());
10+
for (org.web3j.tx.Contract.EventValuesWithLog eventValues : valueList) {
11+
TransferEventResponse typedResponse = new TransferEventResponse();
12+
typedResponse.log = eventValues.getLog();
13+
typedResponse.array = (org.web3j.abi.datatypes.generated.Bytes32) eventValues.getIndexedValues().get(0);
14+
responses.add(typedResponse);
15+
}
16+
return responses;
17+
}
18+
19+
public static TransferEventResponse getTransferEventFromLog(
20+
org.web3j.protocol.core.methods.response.Log log) {
21+
org.web3j.tx.Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSFER_EVENT, log);
22+
TransferEventResponse typedResponse = new TransferEventResponse();
23+
typedResponse.log = log;
24+
typedResponse.array = (org.web3j.abi.datatypes.generated.Bytes32) eventValues.getIndexedValues().get(0);
25+
return typedResponse;
26+
}
27+
28+
public io.reactivex.Flowable<TransferEventResponse> transferEventFlowable(
29+
org.web3j.protocol.core.methods.request.EthFilter filter) {
30+
return web3j.ethLogFlowable(filter).map(log -> getTransferEventFromLog(log));
31+
}
32+
33+
public io.reactivex.Flowable<TransferEventResponse> transferEventFlowable(
34+
org.web3j.protocol.core.DefaultBlockParameter startBlock,
35+
org.web3j.protocol.core.DefaultBlockParameter endBlock) {
36+
org.web3j.protocol.core.methods.request.EthFilter filter = new org.web3j.protocol.core.methods.request.EthFilter(startBlock, endBlock, getContractAddress());
37+
filter.addSingleTopic(org.web3j.abi.EventEncoder.encode(TRANSFER_EVENT));
38+
return transferEventFlowable(filter);
39+
}
40+
41+
public static class TransferEventResponse extends org.web3j.protocol.core.methods.response.BaseEventResponse {
42+
public org.web3j.abi.datatypes.generated.Bytes32 array;
43+
}
44+
}

0 commit comments

Comments
 (0)