Skip to content

Commit b8c4f5d

Browse files
committed
Create Event Signature
1 parent b4f0169 commit b8c4f5d

File tree

8 files changed

+106
-1
lines changed

8 files changed

+106
-1
lines changed

abi-parser/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
<artifactId>jspecify</artifactId>
2424
<scope>compile</scope>
2525
</dependency>
26+
<dependency>
27+
<groupId>com.github.aelstad</groupId>
28+
<artifactId>keccakj</artifactId>
29+
</dependency>
2630
</dependencies>
2731

2832
<build>

abi-parser/src/main/java/com/openelements/hiero/smartcontract/abi/model/AbiEvent.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package com.openelements.hiero.smartcontract.abi.model;
22

3+
import com.openelements.hiero.smartcontract.abi.util.HexConverter;
4+
import com.openelements.hiero.smartcontract.abi.util.KeccakSupport;
5+
import java.nio.charset.StandardCharsets;
36
import java.util.List;
47
import java.util.Objects;
58
import org.jspecify.annotations.NonNull;
6-
import org.jspecify.annotations.Nullable;
79

810
public record AbiEvent(@NonNull String name, @NonNull List<AbiParameter> inputs, boolean anonymous) implements AbiEntry{
911

@@ -16,4 +18,25 @@ public record AbiEvent(@NonNull String name, @NonNull List<AbiParameter> inputs,
1618
public AbiEntryType type() {
1719
return AbiEntryType.EVENT;
1820
}
21+
22+
@NonNull
23+
public String createEventSignature() {
24+
if(!anonymous) {
25+
throw new IllegalStateException("Cannot create anonymous topic for named event");
26+
}
27+
final List<String> canonicalParameterTypes = inputs.stream().map(AbiParameter::getCanonicalType).toList();
28+
return name + "(" + String.join(",", canonicalParameterTypes) + ")";
29+
}
30+
31+
@NonNull
32+
public byte[] createEventSignatureHash() {
33+
final String eventSignature = createEventSignature();
34+
return KeccakSupport.keccak256(eventSignature.getBytes(StandardCharsets.UTF_8));
35+
}
36+
37+
@NonNull
38+
public String createEventSignatureHashAsHex() {
39+
final byte[] eventSignatureHash = createEventSignatureHash();
40+
return HexConverter.bytesToHex(eventSignatureHash);
41+
}
1942
}

abi-parser/src/main/java/com/openelements/hiero/smartcontract/abi/model/AbiParameter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ public record AbiParameter(@NonNull String name, @NonNull AbiParameterType type,
1818
}
1919
}
2020

21+
public String getCanonicalType() {
22+
return type.getCanonicalType();
23+
}
24+
2125
}

abi-parser/src/main/java/com/openelements/hiero/smartcontract/abi/model/AbiParameterType.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,22 @@ public static AbiParameterType of(final String name) {
1818
default -> throw new IllegalArgumentException("Unknown value type: " + name);
1919
};
2020
}
21+
22+
public String getCanonicalType() {
23+
return switch (this) {
24+
case ADDRESS -> "address";
25+
case STRING -> "string";
26+
case BYTE32 -> "bytes32";
27+
case BOOL -> "bool";
28+
case UINT256 -> "uint256";
29+
case TUPLE -> "tuple";
30+
};
31+
}
32+
33+
public boolean isDynamic() {
34+
return switch (this) {
35+
case STRING, BYTE32 -> true;
36+
default -> false;
37+
};
38+
}
2139
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.openelements.hiero.smartcontract.abi.util;
2+
3+
import java.nio.charset.StandardCharsets;
4+
import java.util.Objects;
5+
import org.jspecify.annotations.NonNull;
6+
7+
public class HexConverter {
8+
9+
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
10+
11+
@NonNull
12+
public static String bytesToHex(@NonNull final byte[] bytes) {
13+
//see https://stackoverflow.com/questions/9655181/java-convert-a-byte-array-to-a-hex-string
14+
Objects.requireNonNull(bytes, "bytes");
15+
final byte[] hexChars = new byte[bytes.length * 2];
16+
for (int j = 0; j < bytes.length; j++) {
17+
int v = bytes[j] & 0xFF;
18+
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
19+
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
20+
}
21+
return new String(hexChars, StandardCharsets.UTF_8);
22+
}
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.openelements.hiero.smartcontract.abi.util;
2+
3+
import com.github.aelstad.keccakj.provider.Constants;
4+
import com.github.aelstad.keccakj.provider.KeccakjProvider;
5+
import java.security.MessageDigest;
6+
import java.security.Security;
7+
8+
public class KeccakSupport {
9+
10+
public synchronized static MessageDigest getMessageDigest() {
11+
if(Security.getProvider(Constants.PROVIDER) == null) {
12+
Security.addProvider(new KeccakjProvider());
13+
}
14+
try {
15+
return MessageDigest.getInstance(Constants.SHA3_256, Constants.PROVIDER);
16+
} catch (Exception e) {
17+
throw new RuntimeException("Error in Keccak provisioning", e);
18+
}
19+
}
20+
21+
public static byte[] keccak256(byte[] data) {
22+
MessageDigest md = getMessageDigest();
23+
return md.digest(data);
24+
}
25+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module com.openelements.hiero.smartcontract.abi {
22
exports com.openelements.hiero.smartcontract.abi;
33
exports com.openelements.hiero.smartcontract.abi.model;
4+
exports com.openelements.hiero.smartcontract.abi.util;
45
requires org.jspecify;
6+
requires keccakj;
57
}

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
<cyclonedx-maven-plugin.version>2.8.0</cyclonedx-maven-plugin.version>
6666
<jreleaser-maven-plugin.version>1.9.0</jreleaser-maven-plugin.version>
6767
<versions-maven-plugin.version>2.17.1</versions-maven-plugin.version>
68+
<keccakj.version>1.1.0</keccakj.version>
6869
</properties>
6970

7071
<dependencyManagement>
@@ -191,6 +192,11 @@
191192
<artifactId>gson</artifactId>
192193
<version>${gson.version}</version>
193194
</dependency>
195+
<dependency>
196+
<groupId>com.github.aelstad</groupId>
197+
<artifactId>keccakj</artifactId>
198+
<version>${keccakj.version}</version>
199+
</dependency>
194200
</dependencies>
195201
</dependencyManagement>
196202

0 commit comments

Comments
 (0)