diff --git a/pom.xml b/pom.xml
index 96937f2..a85f062 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@ under the License.
UTF-8
${target.java.version}
${target.java.version}
- 11
+ 24
2.12
2.0.0
2.24.1
@@ -135,8 +135,8 @@ under the License.
maven-compiler-plugin
3.1
- ${target.java.version}
- ${target.java.version}
+ 16
+ 16
diff --git a/src/main/java/stream/DataStreamJob.java b/src/main/java/stream/DataStreamJob.java
index 7b6cc84..7b5767d 100644
--- a/src/main/java/stream/DataStreamJob.java
+++ b/src/main/java/stream/DataStreamJob.java
@@ -20,9 +20,11 @@ package stream;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.streaming.api.datastream.DataStream;
+import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.ParameterTool;
-import stream.dto.ArbitrumOneBlock;
+import stream.dto.*;
+import stream.source.eventlog.EventLogSourceFactory;
import stream.source.newheads.NewHeadsSourceFactory;
import java.io.IOException;
@@ -64,15 +66,19 @@ public class DataStreamJob {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
- DataStream blockStream = env
+ DataStream arbitrumHeads = env
.fromSource(
NewHeadsSourceFactory.createSource(webSocketUri, ArbitrumOneBlock.class),
org.apache.flink.api.common.eventtime.WatermarkStrategy.noWatermarks(),
- "Ethereum Blocks Source",
+ "ArbitrumOne Head Blocks",
TypeInformation.of(ArbitrumOneBlock.class)
);
-
+
+ DataStream mintStream = getEventStream(env, webSocketUri, MintEventLog.SIGNATURE, MintEventLog.class, "Uniswap v3 Mint Events");
+ DataStream burnStream = getEventStream(env, webSocketUri, BurnEventLog.SIGNATURE, BurnEventLog.class, "Uniswap v3 Burn Events");
+
// Map the blocks to pretty-printed JSON strings
+/*
blockStream
.map(block -> {
try {
@@ -83,6 +89,58 @@ public class DataStreamJob {
})
.print("New Ethereum Block: ");
+ transferStream
+ .map(event -> {
+ try {
+ return mapper.writeValueAsString(event);
+ } catch (Exception e) {
+ return "Error converting transfer event to JSON: " + e.getMessage();
+ }
+ })
+ .print("Transfer Event: ");
+
+ swapStream
+ .map(event -> {
+ try {
+ return mapper.writeValueAsString(event);
+ } catch (Exception e) {
+ return "Error converting swap event to JSON: " + e.getMessage();
+ }
+ })
+ .print("Swap Event: ");
+*/
+
+ mintStream
+ .map(event -> {
+ try {
+ return mapper.writeValueAsString(event);
+ } catch (Exception e) {
+ return "Error converting mint event to JSON: " + e.getMessage();
+ }
+ })
+ .print("Mint Event: ");
+
+ burnStream
+ .map(event -> {
+ try {
+ return mapper.writeValueAsString(event);
+ } catch (Exception e) {
+ return "Error converting burn event to JSON: " + e.getMessage();
+ }
+ })
+ .print("Burn Event: ");
+
env.execute("Ethereum Block Stream");
}
+
+ private static DataStreamSource getEventStream(StreamExecutionEnvironment env, URI webSocketUri,
+ String eventSignature, Class eventLogClass, String streamName) {
+ var eventType = new EventType<>(eventSignature, eventLogClass);
+ return env.fromSource(
+ EventLogSourceFactory.createSource(webSocketUri, eventType),
+ org.apache.flink.api.common.eventtime.WatermarkStrategy.noWatermarks(),
+ streamName,
+ TypeInformation.of(eventType.eventLogClass)
+ );
+ }
}
\ No newline at end of file
diff --git a/src/main/java/stream/dto/AddressId.java b/src/main/java/stream/dto/AddressId.java
new file mode 100644
index 0000000..8aefca3
--- /dev/null
+++ b/src/main/java/stream/dto/AddressId.java
@@ -0,0 +1,5 @@
+package stream.dto;
+
+public class AddressId extends ChainId {
+ public String address;
+}
diff --git a/src/main/java/stream/dto/ArbitrumOneBlock.java b/src/main/java/stream/dto/ArbitrumOneBlock.java
index 48f6c4c..fdd8093 100644
--- a/src/main/java/stream/dto/ArbitrumOneBlock.java
+++ b/src/main/java/stream/dto/ArbitrumOneBlock.java
@@ -1,6 +1,10 @@
package stream.dto;
+import java.io.Serial;
+
public class ArbitrumOneBlock extends EthereumBlock {
+ @Serial
+ private static final long serialVersionUID = 1L;
public String l1BlockNumber;
public String sendRoot;
public String sendCount;
@@ -9,5 +13,5 @@ public class ArbitrumOneBlock extends EthereumBlock {
public String l1Hash;
public Long l1Timestamp;
public String sequencerAddress;
-
+
}
diff --git a/src/main/java/stream/dto/BigInt.java b/src/main/java/stream/dto/BigInt.java
new file mode 100644
index 0000000..1c3f206
--- /dev/null
+++ b/src/main/java/stream/dto/BigInt.java
@@ -0,0 +1,20 @@
+package stream.dto;
+
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import stream.io.BigIntDeserializer;
+import stream.io.BigIntSerializer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@JsonSerialize(using = BigIntSerializer.class)
+@JsonDeserialize(using = BigIntDeserializer.class)
+public @interface BigInt {
+}
\ No newline at end of file
diff --git a/src/main/java/stream/dto/Block.java b/src/main/java/stream/dto/Block.java
index dddff13..ec23d74 100644
--- a/src/main/java/stream/dto/Block.java
+++ b/src/main/java/stream/dto/Block.java
@@ -1,5 +1,11 @@
package stream.dto;
-public class Block {
+import java.io.Serial;
+import java.io.Serializable;
+
+public class Block implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
public Long chainId;
}
diff --git a/src/main/java/stream/dto/BlockHash.java b/src/main/java/stream/dto/BlockHash.java
index 04e0414..443ec0b 100644
--- a/src/main/java/stream/dto/BlockHash.java
+++ b/src/main/java/stream/dto/BlockHash.java
@@ -1,6 +1,11 @@
package stream.dto;
+import java.io.Serial;
+
public class BlockHash extends BlockId {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
public String hash;
@Override
diff --git a/src/main/java/stream/dto/BlockId.java b/src/main/java/stream/dto/BlockId.java
index e3a3506..b427a7e 100644
--- a/src/main/java/stream/dto/BlockId.java
+++ b/src/main/java/stream/dto/BlockId.java
@@ -1,6 +1,10 @@
package stream.dto;
+import java.io.Serial;
+
public abstract class BlockId extends Block {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
abstract public Object getId();
}
-
diff --git a/src/main/java/stream/dto/BlockNumber.java b/src/main/java/stream/dto/BlockNumber.java
index c154d38..6aa9b19 100644
--- a/src/main/java/stream/dto/BlockNumber.java
+++ b/src/main/java/stream/dto/BlockNumber.java
@@ -1,6 +1,11 @@
package stream.dto;
+import java.io.Serial;
+
public class BlockNumber extends BlockId {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
public long number;
@Override
diff --git a/src/main/java/stream/dto/BurnEventLog.java b/src/main/java/stream/dto/BurnEventLog.java
new file mode 100644
index 0000000..ffa2505
--- /dev/null
+++ b/src/main/java/stream/dto/BurnEventLog.java
@@ -0,0 +1,39 @@
+package stream.dto;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+
+
+/*
+/// @notice Emitted when a position's liquidity is removed
+/// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
+/// @param owner The owner of the position for which liquidity is removed
+/// @param tickLower The lower tick of the position
+/// @param tickUpper The upper tick of the position
+/// @param amount The amount of liquidity to remove
+/// @param amount0 The amount of token0 withdrawn
+/// @param amount1 The amount of token1 withdrawn
+event Burn(
+ address indexed owner,
+ int24 indexed tickLower,
+ int24 indexed tickUpper,
+ uint128 amount,
+ uint256 amount0,
+ uint256 amount1
+);
+*/
+
+public class BurnEventLog extends EventLog implements Serializable {
+ public static final String SIGNATURE = "Burn(address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)";
+
+ public String owner;
+ public int tickLower;
+ public int tickUpper;
+ @BigInt
+ public BigInteger amount;
+ @BigInt
+ public BigInteger amount0;
+ @BigInt
+ public BigInteger amount1;
+
+}
diff --git a/src/main/java/stream/dto/ChainId.java b/src/main/java/stream/dto/ChainId.java
new file mode 100644
index 0000000..e0b45b6
--- /dev/null
+++ b/src/main/java/stream/dto/ChainId.java
@@ -0,0 +1,7 @@
+package stream.dto;
+
+import java.io.Serializable;
+
+public class ChainId implements Serializable {
+ public int chainId;
+}
diff --git a/src/main/java/stream/dto/ElaboratedEventType.java b/src/main/java/stream/dto/ElaboratedEventType.java
new file mode 100644
index 0000000..0d20e64
--- /dev/null
+++ b/src/main/java/stream/dto/ElaboratedEventType.java
@@ -0,0 +1,158 @@
+package stream.dto;
+
+import org.web3j.abi.FunctionReturnDecoder;
+import org.web3j.abi.TypeReference;
+import org.web3j.abi.datatypes.Address;
+import org.web3j.abi.datatypes.Bool;
+import org.web3j.abi.datatypes.Type;
+import org.web3j.abi.datatypes.Utf8String;
+import org.web3j.abi.datatypes.generated.*;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static stream.io.EthUtils.keccak;
+
+@SuppressWarnings("rawtypes")
+public class ElaboratedEventType extends EventType {
+
+ public transient String name;
+ public transient List paramNames;
+ public transient List> paramTypes;
+ public transient String hash;
+
+ private static final String SIGNATURE_REGEX = "^([a-zA-Z_][a-zA-Z0-9_]*)\\((|[^)]*)\\)$";
+ private static final String PARAM_REGEX = "([a-zA-Z0-9]+(?:\\[(?:[0-9]*|\\s*)])*)\\s+(?:(indexed)\\s+)?([a-zA-Z_][a-zA-Z0-9_]*)";
+
+ public ElaboratedEventType(EventType eventType) {
+ super(eventType.signature, eventType.eventLogClass);
+ var matcher = Pattern.compile(SIGNATURE_REGEX).matcher(signature);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Invalid event signature format: " + signature);
+ }
+ this.name = matcher.group(1);
+ this.paramNames = new ArrayList<>();
+ this.paramTypes = new ArrayList<>();
+ var paramTypeNames = new ArrayList();
+
+ String paramsStr = matcher.group(2).trim();
+ if (!paramsStr.isEmpty()) {
+ var paramMatcher = Pattern.compile(PARAM_REGEX).matcher(paramsStr);
+ while (paramMatcher.find()) {
+ String type = paramMatcher.group(1);
+ boolean indexed = paramMatcher.group(2) != null;
+ String name = paramMatcher.group(3);
+ paramTypeNames.add(type);
+ this.paramNames.add(name);
+ this.paramTypes.add(TypeReference.create(typeMap.get(type), indexed));
+ }
+ }
+ String canonical = this.name+"("+String.join(",", paramTypeNames)+")";
+ this.hash = keccak(canonical);
+ }
+
+ public List