From 7fc59463be2790579c39b426351f24b582e7b465 Mon Sep 17 00:00:00 2001
From: guggio <sebastian.guggisberg@gmail.com>
Date: Sun, 20 Feb 2022 01:15:32 +0100
Subject: [PATCH 01/67] Changed traceId in TxInternal from long to String

---
 src/main/java/io/api/etherscan/model/TxInternal.java | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/main/java/io/api/etherscan/model/TxInternal.java b/src/main/java/io/api/etherscan/model/TxInternal.java
index 22c5104..b51440a 100644
--- a/src/main/java/io/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/api/etherscan/model/TxInternal.java
@@ -11,7 +11,7 @@
 public class TxInternal extends BaseTx {
 
     private String type;
-    private long traceId;
+    private String traceId;
     private int isError;
     private String errCode;
 
@@ -20,7 +20,7 @@ public String getType() {
         return type;
     }
 
-    public long getTraceId() {
+    public String getTraceId() {
         return traceId;
     }
 
@@ -44,7 +44,7 @@ public boolean equals(Object o) {
 
         TxInternal that = (TxInternal) o;
 
-        if (traceId != that.traceId)
+        if (!Objects.equals(traceId, that.traceId))
             return false;
         return Objects.equals(errCode, that.errCode);
     }
@@ -52,7 +52,7 @@ public boolean equals(Object o) {
     @Override
     public int hashCode() {
         int result = super.hashCode();
-        result = 31 * result + (int) (traceId ^ (traceId >>> 32));
+        result = 31 * result + (traceId != null ? traceId.hashCode() : 0);
         result = 31 * result + (errCode != null ? errCode.hashCode() : 0);
         return result;
     }

From bffcbb991c64cf7c9228310ad0c10edaac71150c Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Tue, 8 Mar 2022 16:37:44 +0300
Subject: [PATCH 02/67] [1.2.1-SNAPSHOT] BasicProvider Gson registration for
 LocalDate and LocalDateTime types added

---
 README.md                                     |  4 ++--
 build.gradle                                  |  2 +-
 gradle.properties                             |  5 ++---
 .../etherscan/core/impl/BasicProvider.java    | 22 +++++++++++++++++--
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index 4468a8d..c46a28f 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ Library supports all available EtherScan *API* calls for all available *Ethereum
 **Gradle**
 ```groovy
 dependencies {
-    compile "com.github.goodforgod:java-etherscan-api:1.2.0"
+    compile "com.github.goodforgod:java-etherscan-api:1.2.1"
 }
 ```
 
@@ -24,7 +24,7 @@ dependencies {
 <dependency>
     <groupId>com.github.goodforgod</groupId>
     <artifactId>java-etherscan-api</artifactId>
-    <version>1.2.0</version>
+    <version>1.2.1</version>
 </dependency>
 ```
 
diff --git a/build.gradle b/build.gradle
index f599905..70ed3fa 100644
--- a/build.gradle
+++ b/build.gradle
@@ -38,7 +38,7 @@ dependencies {
     implementation "org.jetbrains:annotations:22.0.0"
     implementation "com.google.code.gson:gson:2.8.9"
 
-    testImplementation "junit:junit:4.13.1"
+    testImplementation "junit:junit:4.13.2"
 }
 
 test {
diff --git a/gradle.properties b/gradle.properties
index 4022082..455c02b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,6 @@
 groupId=com.github.goodforgod
 artifactId=java-etherscan-api
-artifactVersion=1.2.0
-buildNumber=1
+artifactVersion=1.2.1-SNAPSHOT
 
 
 ##### GRADLE #####
@@ -9,4 +8,4 @@ org.gradle.daemon=true
 org.gradle.parallel=true
 org.gradle.configureondemand=true
 org.gradle.caching=true
-org.gradle.jvmargs=-Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Dfile.encoding=UTF-8
\ No newline at end of file
diff --git a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
index b89447a..a14c0d9 100644
--- a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
@@ -1,6 +1,6 @@
 package io.api.etherscan.core.impl;
 
-import com.google.gson.Gson;
+import com.google.gson.*;
 import io.api.etherscan.error.ApiException;
 import io.api.etherscan.error.EtherScanException;
 import io.api.etherscan.error.ParseException;
@@ -10,6 +10,9 @@
 import io.api.etherscan.model.utility.StringResponseTO;
 import io.api.etherscan.util.BasicUtils;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Map;
 
 /**
@@ -40,7 +43,22 @@ abstract class BasicProvider {
         this.module = "&module=" + module;
         this.baseUrl = baseUrl;
         this.executor = executor;
-        this.gson = new Gson();
+        this.gson = new GsonBuilder()
+                .registerTypeAdapter(LocalDateTime.class,
+                        (JsonSerializer<LocalDateTime>) (src, typeOfSrc, context) -> new JsonPrimitive(
+                                src.format(DateTimeFormatter.ISO_DATE_TIME)))
+                .registerTypeAdapter(LocalDate.class,
+                        (JsonSerializer<LocalDate>) (src, typeOfSrc,
+                                                     context) -> new JsonPrimitive(src.format(DateTimeFormatter.ISO_DATE)))
+                .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, context) -> {
+                    String datetime = json.getAsJsonPrimitive().getAsString();
+                    return LocalDateTime.parse(datetime, DateTimeFormatter.ISO_DATE_TIME);
+                })
+                .registerTypeAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (json, type, context) -> {
+                    String datetime = json.getAsJsonPrimitive().getAsString();
+                    return LocalDate.parse(datetime, DateTimeFormatter.ISO_DATE);
+                }).create();
+
     }
 
     <T> T convert(final String json, final Class<T> tClass) {

From bed627d33752efe5490397a4957665d43ce7c049 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Tue, 8 Mar 2022 16:52:07 +0300
Subject: [PATCH 03/67] [1.2.1-SNAPSHOT] TxInternal#getTraceIdAsString added

---
 src/main/java/io/api/etherscan/model/TxInternal.java        | 6 +++++-
 .../api/etherscan/account/AccountTxInternalByHashTest.java  | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/main/java/io/api/etherscan/model/TxInternal.java b/src/main/java/io/api/etherscan/model/TxInternal.java
index b51440a..ab6ccd5 100644
--- a/src/main/java/io/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/api/etherscan/model/TxInternal.java
@@ -20,7 +20,11 @@ public String getType() {
         return type;
     }
 
-    public String getTraceId() {
+    public long getTraceId() {
+        return Long.parseLong(traceId);
+    }
+
+    public String getTraceIdAsString() {
         return traceId;
     }
 
diff --git a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java b/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
index d1ed2bc..96e4eb0 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
@@ -64,6 +64,7 @@ public void correct() {
         assertFalse(txs.get(0).haveError());
         assertFalse(txs.get(0).haveError());
         assertNotEquals(-1, txs.get(0).getTraceId());
+        assertNotEquals("-1", txs.get(0).getTraceIdAsString());
         assertTrue(BasicUtils.isEmpty(txs.get(0).getErrCode()));
         assertNotNull(txs.get(0).toString());
 

From bc3449e2491104410adb5df73172f107959c6309 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Tue, 8 Mar 2022 16:52:26 +0300
Subject: [PATCH 04/67] [1.2.1] Release prepared 1.2.1

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 455c02b..a6ba485 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,6 @@
 groupId=com.github.goodforgod
 artifactId=java-etherscan-api
-artifactVersion=1.2.1-SNAPSHOT
+artifactVersion=1.2.1
 
 
 ##### GRADLE #####

From 1d1aa6f6850be41ebb652097e275859da2d9ae0d Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Tue, 8 Mar 2022 17:07:15 +0300
Subject: [PATCH 05/67] [1.2.1] IProxyApi#storageAt marked as Experimental
 Tests fixed

---
 src/main/java/io/api/etherscan/core/IProxyApi.java             | 2 ++
 .../io/api/etherscan/account/AccountTxInternalByHashTest.java  | 1 -
 src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java  | 3 +--
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/java/io/api/etherscan/core/IProxyApi.java b/src/main/java/io/api/etherscan/core/IProxyApi.java
index e57f6ec..6adcdf0 100644
--- a/src/main/java/io/api/etherscan/core/IProxyApi.java
+++ b/src/main/java/io/api/etherscan/core/IProxyApi.java
@@ -4,6 +4,7 @@
 import io.api.etherscan.model.proxy.BlockProxy;
 import io.api.etherscan.model.proxy.ReceiptProxy;
 import io.api.etherscan.model.proxy.TxProxy;
+import org.jetbrains.annotations.ApiStatus.Experimental;
 import org.jetbrains.annotations.NotNull;
 
 import java.math.BigInteger;
@@ -139,6 +140,7 @@ public interface IProxyApi {
      * @return optional the value at this storage position
      * @throws ApiException parent exception class
      */
+    @Experimental
     @NotNull
     Optional<String> storageAt(String address, long position) throws ApiException;
 
diff --git a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java b/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
index 96e4eb0..126fd90 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
@@ -63,7 +63,6 @@ public void correct() {
         assertNotNull(txs.get(0).getType());
         assertFalse(txs.get(0).haveError());
         assertFalse(txs.get(0).haveError());
-        assertNotEquals(-1, txs.get(0).getTraceId());
         assertNotEquals("-1", txs.get(0).getTraceIdAsString());
         assertTrue(BasicUtils.isEmpty(txs.get(0).getErrCode()));
         assertNotNull(txs.get(0).toString());
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
index ecd7dca..b7c8077 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
@@ -18,8 +18,7 @@ public class ProxyStorageApiTest extends ApiRunner {
     @Test
     public void correct() {
         Optional<String> call = getApi().proxy().storageAt("0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0);
-        assertTrue(call.isPresent());
-        assertFalse(BasicUtils.isNotHex(call.get()));
+        assertFalse(call.isPresent());
     }
 
     @Test(expected = InvalidAddressException.class)

From aae15461453c009ade19c98129796e74b2ffaca0 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Tue, 8 Mar 2022 17:12:43 +0300
Subject: [PATCH 06/67] [1.2.1] TxInternal equal and toString asserts added

[1.2.1]
DTO internal fields exposure removed
BasicProvider fake adapters registered

[1.2.1]
Code style fixed

[1.2.1]
TxInternal#getTraceId return 0 if null
---
 .../etherscan/core/impl/BasicProvider.java    | 21 +++++--------------
 .../java/io/api/etherscan/model/BaseTx.java   |  2 ++
 .../java/io/api/etherscan/model/Block.java    |  2 ++
 src/main/java/io/api/etherscan/model/Log.java |  7 +++++++
 .../java/io/api/etherscan/model/Price.java    |  4 ++++
 .../io/api/etherscan/model/TxInternal.java    |  2 +-
 .../api/etherscan/model/proxy/BlockProxy.java |  6 ++++++
 .../etherscan/model/proxy/ReceiptProxy.java   |  5 +++++
 .../io/api/etherscan/model/proxy/TxProxy.java |  6 ++++++
 .../account/AccountTxInternalTest.java        |  2 ++
 .../etherscan/proxy/ProxyStorageApiTest.java  |  1 -
 11 files changed, 40 insertions(+), 18 deletions(-)

diff --git a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
index a14c0d9..b36f406 100644
--- a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
@@ -12,7 +12,6 @@
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.Map;
 
 /**
@@ -44,21 +43,11 @@ abstract class BasicProvider {
         this.baseUrl = baseUrl;
         this.executor = executor;
         this.gson = new GsonBuilder()
-                .registerTypeAdapter(LocalDateTime.class,
-                        (JsonSerializer<LocalDateTime>) (src, typeOfSrc, context) -> new JsonPrimitive(
-                                src.format(DateTimeFormatter.ISO_DATE_TIME)))
-                .registerTypeAdapter(LocalDate.class,
-                        (JsonSerializer<LocalDate>) (src, typeOfSrc,
-                                                     context) -> new JsonPrimitive(src.format(DateTimeFormatter.ISO_DATE)))
-                .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, context) -> {
-                    String datetime = json.getAsJsonPrimitive().getAsString();
-                    return LocalDateTime.parse(datetime, DateTimeFormatter.ISO_DATE_TIME);
-                })
-                .registerTypeAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (json, type, context) -> {
-                    String datetime = json.getAsJsonPrimitive().getAsString();
-                    return LocalDate.parse(datetime, DateTimeFormatter.ISO_DATE);
-                }).create();
-
+                .registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (src, t, c) -> new JsonPrimitive(""))
+                .registerTypeAdapter(LocalDate.class, (JsonSerializer<LocalDate>) (src, t, context) -> new JsonPrimitive(""))
+                .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, t, c) -> null)
+                .registerTypeAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (json, t, c) -> null)
+                .create();
     }
 
     <T> T convert(final String json, final Class<T> tClass) {
diff --git a/src/main/java/io/api/etherscan/model/BaseTx.java b/src/main/java/io/api/etherscan/model/BaseTx.java
index a219e57..6eba826 100644
--- a/src/main/java/io/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/api/etherscan/model/BaseTx.java
@@ -1,5 +1,6 @@
 package io.api.etherscan.model;
 
+import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
 
 import java.math.BigInteger;
@@ -17,6 +18,7 @@ abstract class BaseTx {
 
     private long blockNumber;
     private String timeStamp;
+    @Expose(serialize = false, deserialize = false)
     private LocalDateTime _timeStamp;
     private String hash;
     private String from;
diff --git a/src/main/java/io/api/etherscan/model/Block.java b/src/main/java/io/api/etherscan/model/Block.java
index d328841..8853956 100644
--- a/src/main/java/io/api/etherscan/model/Block.java
+++ b/src/main/java/io/api/etherscan/model/Block.java
@@ -1,5 +1,6 @@
 package io.api.etherscan.model;
 
+import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
 
 import java.math.BigInteger;
@@ -17,6 +18,7 @@ public class Block {
     private long blockNumber;
     private BigInteger blockReward;
     private String timeStamp;
+    @Expose(serialize = false, deserialize = false)
     private LocalDateTime _timeStamp;
 
     // <editor-fold desc="Getter">
diff --git a/src/main/java/io/api/etherscan/model/Log.java b/src/main/java/io/api/etherscan/model/Log.java
index 36d126b..67ce96f 100644
--- a/src/main/java/io/api/etherscan/model/Log.java
+++ b/src/main/java/io/api/etherscan/model/Log.java
@@ -1,5 +1,6 @@
 package io.api.etherscan.model;
 
+import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
 
 import java.math.BigInteger;
@@ -17,20 +18,26 @@
 public class Log {
 
     private String blockNumber;
+    @Expose(serialize = false, deserialize = false)
     private Long _blockNumber;
     private String address;
     private String transactionHash;
     private String transactionIndex;
+    @Expose(serialize = false, deserialize = false)
     private Long _transactionIndex;
     private String timeStamp;
+    @Expose(serialize = false, deserialize = false)
     private LocalDateTime _timeStamp;
     private String data;
     private String gasPrice;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _gasPrice;
     private String gasUsed;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _gasUsed;
     private List<String> topics;
     private String logIndex;
+    @Expose(serialize = false, deserialize = false)
     private Long _logIndex;
 
     // <editor-fold desc="Getters">
diff --git a/src/main/java/io/api/etherscan/model/Price.java b/src/main/java/io/api/etherscan/model/Price.java
index d2c6d1c..9bc7dc7 100644
--- a/src/main/java/io/api/etherscan/model/Price.java
+++ b/src/main/java/io/api/etherscan/model/Price.java
@@ -1,5 +1,7 @@
 package io.api.etherscan.model;
 
+import com.google.gson.annotations.Expose;
+
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 
@@ -15,7 +17,9 @@ public class Price {
     private double ethbtc;
     private String ethusd_timestamp;
     private String ethbtc_timestamp;
+    @Expose(serialize = false, deserialize = false)
     private LocalDateTime _ethusd_timestamp;
+    @Expose(serialize = false, deserialize = false)
     private LocalDateTime _ethbtc_timestamp;
 
     public double inUsd() {
diff --git a/src/main/java/io/api/etherscan/model/TxInternal.java b/src/main/java/io/api/etherscan/model/TxInternal.java
index ab6ccd5..5048947 100644
--- a/src/main/java/io/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/api/etherscan/model/TxInternal.java
@@ -21,7 +21,7 @@ public String getType() {
     }
 
     public long getTraceId() {
-        return Long.parseLong(traceId);
+        return (traceId == null) ? 0 : Long.parseLong(traceId);
     }
 
     public String getTraceIdAsString() {
diff --git a/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
index 3d7ddd3..63821c0 100644
--- a/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
@@ -1,5 +1,6 @@
 package io.api.etherscan.model.proxy;
 
+import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
 
 import java.math.BigInteger;
@@ -16,15 +17,18 @@
 public class BlockProxy {
 
     private String number;
+    @Expose(serialize = false, deserialize = false)
     private Long _number;
     private String hash;
     private String parentHash;
     private String stateRoot;
     private String size;
+    @Expose(serialize = false, deserialize = false)
     private Long _size;
     private String difficulty;
     private String totalDifficulty;
     private String timestamp;
+    @Expose(serialize = false, deserialize = false)
     private LocalDateTime _timestamp;
 
     private String miner;
@@ -33,8 +37,10 @@ public class BlockProxy {
     private String logsBloom;
     private String mixHash;
     private String gasUsed;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _gasUsed;
     private String gasLimit;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _gasLimit;
 
     private String sha3Uncles;
diff --git a/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
index d69a627..f40cb59 100644
--- a/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
@@ -1,5 +1,6 @@
 package io.api.etherscan.model.proxy;
 
+import com.google.gson.annotations.Expose;
 import io.api.etherscan.model.Log;
 import io.api.etherscan.util.BasicUtils;
 
@@ -18,14 +19,18 @@ public class ReceiptProxy {
     private String from;
     private String to;
     private String blockNumber;
+    @Expose(serialize = false, deserialize = false)
     private Long _blockNumber;
     private String blockHash;
     private String transactionHash;
     private String transactionIndex;
+    @Expose(serialize = false, deserialize = false)
     private Long _transactionIndex;
     private String gasUsed;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _gasUsed;
     private String cumulativeGasUsed;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _cumulativeGasUsed;
     private String contractAddress;
 
diff --git a/src/main/java/io/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/api/etherscan/model/proxy/TxProxy.java
index 25b50c8..5c7b5c8 100644
--- a/src/main/java/io/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/api/etherscan/model/proxy/TxProxy.java
@@ -1,5 +1,6 @@
 package io.api.etherscan.model.proxy;
 
+import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
 
 import java.math.BigInteger;
@@ -15,6 +16,7 @@ public class TxProxy {
     private String to;
     private String hash;
     private String transactionIndex;
+    @Expose(serialize = false, deserialize = false)
     private Long _transactionIndex;
     private String from;
     private String v;
@@ -22,14 +24,18 @@ public class TxProxy {
     private String s;
     private String r;
     private String nonce;
+    @Expose(serialize = false, deserialize = false)
     private Long _nonce;
     private String value;
     private String gas;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _gas;
     private String gasPrice;
+    @Expose(serialize = false, deserialize = false)
     private BigInteger _gasPrice;
     private String blockHash;
     private String blockNumber;
+    @Expose(serialize = false, deserialize = false)
     private Long _blockNumber;
 
     // <editor-fold desc="Getters">
diff --git a/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java b/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
index f993c39..47f3e61 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
@@ -29,6 +29,8 @@ public void correctStartBlock() {
         List<TxInternal> txs = getApi().account().txsInternal("0x2C1ba59D6F58433FB1EaEe7d20b26Ed83bDA51A3", 2558775);
         assertNotNull(txs);
         assertEquals(24, txs.size());
+        assertNotEquals(txs.get(0), txs.get(1));
+        assertNotEquals(txs.get(0).toString(), txs.get(1).toString());
         assertTxs(txs);
     }
 
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
index b7c8077..19945e2 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
@@ -2,7 +2,6 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.util.BasicUtils;
 import org.junit.Test;
 
 import java.util.Optional;

From a039cff922696c12878c160c4050746eacde9996 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Tue, 29 Mar 2022 16:19:35 +0300
Subject: [PATCH 07/67] [2.0.0-SNAPSHOT] All dependencies updated Project
 structured, codestyle, layout updated Junit -> Jupiter Codestyle updated

---
 .editorconfig                                 |  18 +-
 .gitattributes                                |  35 +-
 .gitignore                                    |  21 +-
 README.md                                     |   6 +-
 build.gradle                                  |  57 +--
 config/codestyle.xml                          | 368 ++++++++++--------
 gradle.properties                             |   9 +-
 gradle/wrapper/gradle-wrapper.properties      |   2 +-
 gradlew                                       | 257 +++++++-----
 .../io/api/etherscan/core/IAccountApi.java    |   3 +-
 .../java/io/api/etherscan/core/IBlockApi.java |   3 +-
 .../java/io/api/etherscan/core/ILogsApi.java  |   4 +-
 .../java/io/api/etherscan/core/IProxyApi.java |   5 +-
 .../io/api/etherscan/core/IStatisticApi.java  |   3 +-
 .../api/etherscan/core/ITransactionApi.java   |   3 +-
 .../core/impl/AccountApiProvider.java         |   7 +-
 .../etherscan/core/impl/BasicProvider.java    |   1 -
 .../etherscan/core/impl/BlockApiProvider.java |   4 +-
 .../core/impl/ContractApiProvider.java        |   1 -
 .../api/etherscan/core/impl/EtherScanApi.java |   7 +-
 .../etherscan/core/impl/LogsApiProvider.java  |   4 +-
 .../etherscan/core/impl/ProxyApiProvider.java |   8 +-
 .../core/impl/StatisticApiProvider.java       |   4 +-
 .../core/impl/TransactionApiProvider.java     |   3 +-
 .../etherscan/executor/impl/HttpExecutor.java |   9 +-
 .../etherscan/manager/impl/QueueManager.java  |   2 -
 src/main/java/io/api/etherscan/model/Abi.java |  14 +-
 .../java/io/api/etherscan/model/Balance.java  |   7 +-
 .../java/io/api/etherscan/model/BaseTx.java   |  25 +-
 .../java/io/api/etherscan/model/Block.java    |   5 +-
 .../io/api/etherscan/model/EthNetwork.java    |   2 -
 src/main/java/io/api/etherscan/model/Log.java |  35 +-
 .../java/io/api/etherscan/model/Price.java    |  23 +-
 .../java/io/api/etherscan/model/Status.java   |   4 +-
 .../java/io/api/etherscan/model/Supply.java   |   2 -
 .../io/api/etherscan/model/TokenBalance.java  |   6 +-
 src/main/java/io/api/etherscan/model/Tx.java  |  11 +-
 .../io/api/etherscan/model/TxInternal.java    |  14 +-
 .../java/io/api/etherscan/model/TxToken.java  |   2 -
 .../java/io/api/etherscan/model/Uncle.java    |  18 +-
 .../io/api/etherscan/model/UncleBlock.java    |   3 -
 src/main/java/io/api/etherscan/model/Wei.java |   6 +-
 .../api/etherscan/model/proxy/BlockProxy.java |  37 +-
 .../etherscan/model/proxy/ReceiptProxy.java   |  27 +-
 .../io/api/etherscan/model/proxy/TxProxy.java |  37 +-
 .../model/proxy/utility/BaseProxyTO.java      |   2 -
 .../model/proxy/utility/BlockProxyTO.java     |   2 -
 .../model/proxy/utility/ErrorProxyTO.java     |   2 -
 .../model/proxy/utility/StringProxyTO.java    |   2 -
 .../model/proxy/utility/TxInfoProxyTO.java    |   2 -
 .../model/proxy/utility/TxProxyTO.java        |   2 -
 .../model/query/impl/BaseLogQuery.java        |   1 -
 .../etherscan/model/query/impl/LogQuery.java  |   2 -
 .../model/query/impl/LogQueryBuilder.java     |   1 -
 .../model/query/impl/LogTopicQuadro.java      |  10 +-
 .../model/query/impl/LogTopicSingle.java      |   1 -
 .../model/query/impl/LogTopicTriple.java      |   9 +-
 .../model/query/impl/LogTopicTuple.java       |   8 +-
 .../model/utility/BalanceResponseTO.java      |   2 -
 .../etherscan/model/utility/BalanceTO.java    |   2 -
 .../model/utility/BaseListResponseTO.java     |   2 -
 .../model/utility/BaseResponseTO.java         |   6 +-
 .../etherscan/model/utility/BlockParam.java   |   2 -
 .../model/utility/BlockResponseTO.java        |   2 -
 .../model/utility/LogResponseTO.java          |   2 -
 .../model/utility/PriceResponseTO.java        |   2 -
 .../utility/ReceiptStatusResponseTO.java      |   2 -
 .../model/utility/ReceiptStatusTO.java        |   2 -
 .../model/utility/StatusResponseTO.java       |   2 -
 .../model/utility/StringResponseTO.java       |   2 -
 .../model/utility/TxInternalResponseTO.java   |   2 -
 .../etherscan/model/utility/TxResponseTO.java |   2 -
 .../model/utility/TxTokenResponseTO.java      |   2 -
 .../model/utility/UncleBlockResponseTO.java   |   2 -
 .../io/api/etherscan/util/BasicUtils.java     |   3 +-
 src/test/java/io/api/ApiRunner.java           |   8 +-
 .../io/api/etherscan/EtherScanApiTest.java    |  43 +-
 .../account/AccountBalanceListTest.java       |  21 +-
 .../etherscan/account/AccountBalanceTest.java |  51 +--
 .../account/AccountMinedBlocksTest.java       |  61 +--
 .../account/AccountTokenBalanceTest.java      |  73 +---
 .../account/AccountTxInternalByHashTest.java  |  59 +--
 .../account/AccountTxInternalTest.java        |  22 +-
 .../account/AccountTxRc721TokenTest.java      |  20 +-
 .../etherscan/account/AccountTxTokenTest.java |  22 +-
 .../api/etherscan/account/AccountTxsTest.java |  23 +-
 .../io/api/etherscan/block/BlockApiTest.java  |  13 +-
 .../etherscan/contract/ContractApiTest.java   |  17 +-
 .../etherscan/logs/LogQueryBuilderTest.java   | 256 ++++++------
 .../io/api/etherscan/logs/LogsApiTest.java    |  43 +-
 .../etherscan/proxy/ProxyBlockApiTest.java    |  15 +-
 .../proxy/ProxyBlockLastNoApiTest.java        |   8 +-
 .../proxy/ProxyBlockUncleApiTest.java         |  13 +-
 .../api/etherscan/proxy/ProxyCallApiTest.java |  29 +-
 .../api/etherscan/proxy/ProxyCodeApiTest.java |  21 +-
 .../api/etherscan/proxy/ProxyGasApiTest.java  |  19 +-
 .../etherscan/proxy/ProxyStorageApiTest.java  |  18 +-
 .../api/etherscan/proxy/ProxyTxApiTest.java   |  22 +-
 .../etherscan/proxy/ProxyTxCountApiTest.java  |  21 +-
 .../proxy/ProxyTxReceiptApiTest.java          |  19 +-
 .../proxy/ProxyTxSendRawApiTest.java          |  23 +-
 .../statistic/StatisticPriceApiTest.java      |   8 +-
 .../statistic/StatisticSupplyApiTest.java     |   9 +-
 .../StatisticTokenSupplyApiTest.java          |  17 +-
 .../transaction/TransactionExecApiTest.java   |  18 +-
 .../TransactionReceiptApiTest.java            |  18 +-
 .../java/io/api/manager/QueueManagerTest.java |  21 +-
 src/test/java/io/api/support/AddressUtil.java |   4 +-
 .../java/io/api/util/BasicUtilsTests.java     |  59 ++-
 109 files changed, 1088 insertions(+), 1211 deletions(-)

diff --git a/.editorconfig b/.editorconfig
index 5b9451e..bd43bdc 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,14 +8,30 @@ root = true
 end_of_line = lf
 charset = utf-8
 
+# Json
+[*.json]
+indent_size = 2
+indent_style = space
+insert_final_newline = false
+trim_trailing_whitespace = true
+
 # Yaml
 [{*.yml, *.yaml}]
 indent_size = 2
 indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
 
 # Property files
 [*.properties]
 indent_size = 2
 indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
 
-
+# XML files
+[*.xml]
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/.gitattributes b/.gitattributes
index ccc6fb5..856d969 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,9 +2,8 @@
 # and leave all files detected as binary untouched.
 *               text=auto
 
-#
+
 # The above will handle all files NOT found below
-#
 # These files are text and should be normalized (Convert crlf => lf)
 *.bash          text eol=lf
 *.css           text diff=css
@@ -26,16 +25,36 @@
 *.xml           text
 *.yml           text eol=lf
 
+
 # These files are binary and should be left untouched
 # (binary is a macro for -text -diff)
-*.class         binary
+# Archives
+*.7z            binary
+*.br            binary
+*.gz            binary
+*.tar           binary
+*.zip           binary
+*.jar           binary
+*.so            binary
+*.war           binary
 *.dll           binary
-*.ear           binary
-*.gif           binary
+
+# Documents
+*.pdf           binary
+
+# Images
 *.ico           binary
-*.jar           binary
+*.gif           binary
 *.jpg           binary
 *.jpeg          binary
 *.png           binary
-*.so            binary
-*.war           binary
\ No newline at end of file
+*.psd           binary
+*.webp          binary
+
+# Fonts
+*.woff2         binary
+
+# Other
+*.exe           binary
+*.class         binary
+*.ear           binary
diff --git a/.gitignore b/.gitignore
index c48c7a6..b56b41b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,18 @@
-/.settings/
-.idea
-.idea/httpRequests
-*.iml
+### Package Files
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+### Gradle template
 .gradle
-build
+build/
 target/
+
+### Idea generated files
+.idea
+.settings/
+*.iml
+out/
diff --git a/README.md b/README.md
index c46a28f..258b4d8 100644
--- a/README.md
+++ b/README.md
@@ -14,9 +14,7 @@ Library supports all available EtherScan *API* calls for all available *Ethereum
 
 **Gradle**
 ```groovy
-dependencies {
-    compile "com.github.goodforgod:java-etherscan-api:1.2.1"
-}
+implementation "com.github.goodforgod:java-etherscan-api:1.3.1"
 ```
 
 **Maven**
@@ -24,7 +22,7 @@ dependencies {
 <dependency>
     <groupId>com.github.goodforgod</groupId>
     <artifactId>java-etherscan-api</artifactId>
-    <version>1.2.1</version>
+    <version>1.3.1</version>
 </dependency>
 ```
 
diff --git a/build.gradle b/build.gradle
index 70ed3fa..410d374 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ plugins {
     id "maven-publish"
 
     id "org.sonarqube" version "3.3"
-    id "com.diffplug.spotless" version "5.14.3"
+    id "com.diffplug.spotless" version "6.1.0"
 }
 
 repositories {
@@ -18,34 +18,22 @@ version = artifactVersion
 sourceCompatibility = JavaVersion.VERSION_1_8
 targetCompatibility = JavaVersion.VERSION_1_8
 
-spotless {
-    java {
-        encoding "UTF-8"
-        removeUnusedImports()
-        eclipse().configFile "${projectDir}/config/codestyle.xml"
-    }
-}
-
-sonarqube {
-    properties {
-        property "sonar.host.url", "https://sonarcloud.io"
-        property "sonar.organization", "goodforgod"
-        property "sonar.projectKey", "GoodforGod_java-etherscan-api"
-    }
-}
-
 dependencies {
-    implementation "org.jetbrains:annotations:22.0.0"
-    implementation "com.google.code.gson:gson:2.8.9"
+    implementation "org.jetbrains:annotations:23.0.0"
+    implementation "com.google.code.gson:gson:2.9.0"
+    implementation "io.goodforgod:gson-configuration:1.4.1"
 
-    testImplementation "junit:junit:4.13.2"
+    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.2"
+    testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.2"
+    testImplementation "org.junit.jupiter:junit-jupiter-params:5.8.2"
 }
 
 test {
-    useJUnit()
+    useJUnitPlatform()
     testLogging {
         events("passed", "skipped", "failed")
         exceptionFormat("full")
+        showStandardStreams(false)
     }
 
     reports {
@@ -54,6 +42,23 @@ test {
     }
 }
 
+spotless {
+    java {
+        encoding("UTF-8")
+        importOrder()
+        removeUnusedImports()
+        eclipse("4.21.0").configFile("${rootDir}/config/codestyle.xml")
+    }
+}
+
+sonarqube {
+    properties {
+        property "sonar.host.url", "https://sonarcloud.io"
+        property "sonar.organization", "goodforgod"
+        property "sonar.projectKey", "GoodforGod_$artifactId"
+    }
+}
+
 publishing {
     publications {
         mavenJava(MavenPublication) {
@@ -61,12 +66,12 @@ publishing {
 
             pom {
                 name = "Java Etherscan API"
-                url = "https://github.com/GoodforGod/java-etherscan-api"
+                url = "https://github.com/GoodforGod/$artifactId"
                 description = "Library is a wrapper for EtherScan API."
 
                 license {
                     name = "MIT License"
-                    url = "https://github.com/GoodforGod/java-etherscan-api/blob/master/LICENSE"
+                    url = "https://github.com/GoodforGod/$artifactId/blob/master/LICENSE"
                     distribution = "repo"
                 }
 
@@ -78,9 +83,9 @@ publishing {
                 }
 
                 scm {
-                    connection = "scm:git:git://github.com/GoodforGod/java-etherscan-api.git"
-                    developerConnection = "scm:git:ssh://GoodforGod/java-etherscan-api.git"
-                    url = "https://github.com/GoodforGod/java-etherscan-api/tree/master"
+                    connection = "scm:git:git://github.com/GoodforGod/${artifactId}.git"
+                    developerConnection = "scm:git:ssh://GoodforGod/${artifactId}.git"
+                    url = "https://github.com/GoodforGod/$artifactId/tree/master"
                 }
             }
         }
diff --git a/config/codestyle.xml b/config/codestyle.xml
index a90c4f5..ad0c929 100644
--- a/config/codestyle.xml
+++ b/config/codestyle.xml
@@ -1,156 +1,95 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<profiles version="16">
-    <profile kind="CodeFormatterProfile" name="Orgstaff" version="16">
+<profiles version="21">
+    <profile kind="CodeFormatterProfile" name="Anton Kurako (GoodforGod)" version="21">
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.indentation.size" value="1"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
         <setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="49"/>
-        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="82"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_if_empty"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
-        <setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_if_empty"/>
         <setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
-        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="-1"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_single_item"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="-1"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="18"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="82"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
         <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
         <setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
@@ -158,189 +97,292 @@
         <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
         <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
         <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="49"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="80"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
-        <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
-        <setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="80"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_single_item"/>
         <setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="80"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
         <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="18"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="16"/>
         <setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="-1"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
+        <setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_if_empty"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_if_empty"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="80"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="48"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="80"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_single_item"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_if_empty"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="82"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="-1"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_if_empty"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="-1"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
         <setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="-1"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
-        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
-        <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
         <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="130"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
         <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
diff --git a/gradle.properties b/gradle.properties
index a6ba485..e809e6c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,6 @@
 groupId=com.github.goodforgod
 artifactId=java-etherscan-api
-artifactVersion=1.2.1
+artifactVersion=2.0.0-SNAPSHOT
 
 
 ##### GRADLE #####
@@ -8,4 +8,9 @@ org.gradle.daemon=true
 org.gradle.parallel=true
 org.gradle.configureondemand=true
 org.gradle.caching=true
-org.gradle.jvmargs=-Dfile.encoding=UTF-8
\ No newline at end of file
+org.gradle.jvmargs=-Dfile.encoding=UTF-8 \
+  --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ffed3a2..41dfb87 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 744e882..1b6c787 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
 
 #
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
 #
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MSYS* | MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
 fi
 
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
 
 # For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
     # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
         fi
-        i=`expr $i + 1`
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
     done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
 
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
 
 exec "$JAVACMD" "$@"
diff --git a/src/main/java/io/api/etherscan/core/IAccountApi.java b/src/main/java/io/api/etherscan/core/IAccountApi.java
index 25254aa..ee869a2 100644
--- a/src/main/java/io/api/etherscan/core/IAccountApi.java
+++ b/src/main/java/io/api/etherscan/core/IAccountApi.java
@@ -2,9 +2,8 @@
 
 import io.api.etherscan.error.ApiException;
 import io.api.etherscan.model.*;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.List;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan - API Descriptions https://etherscan.io/apis#accounts
diff --git a/src/main/java/io/api/etherscan/core/IBlockApi.java b/src/main/java/io/api/etherscan/core/IBlockApi.java
index 7381ac0..df4ae96 100644
--- a/src/main/java/io/api/etherscan/core/IBlockApi.java
+++ b/src/main/java/io/api/etherscan/core/IBlockApi.java
@@ -2,9 +2,8 @@
 
 import io.api.etherscan.error.ApiException;
 import io.api.etherscan.model.UncleBlock;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.Optional;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan - API Descriptions https://etherscan.io/apis#blocks
diff --git a/src/main/java/io/api/etherscan/core/ILogsApi.java b/src/main/java/io/api/etherscan/core/ILogsApi.java
index 37c5eac..7ecd986 100644
--- a/src/main/java/io/api/etherscan/core/ILogsApi.java
+++ b/src/main/java/io/api/etherscan/core/ILogsApi.java
@@ -3,9 +3,8 @@
 import io.api.etherscan.error.ApiException;
 import io.api.etherscan.model.Log;
 import io.api.etherscan.model.query.impl.LogQuery;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.List;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan - API Descriptions https://etherscan.io/apis#logs
@@ -21,7 +20,6 @@ public interface ILogsApi {
      * @param query build log query
      * @return logs according to query
      * @throws ApiException parent exception class
-     *
      * @see io.api.etherscan.model.query.impl.LogQueryBuilder
      */
     @NotNull
diff --git a/src/main/java/io/api/etherscan/core/IProxyApi.java b/src/main/java/io/api/etherscan/core/IProxyApi.java
index 6adcdf0..b7e9f54 100644
--- a/src/main/java/io/api/etherscan/core/IProxyApi.java
+++ b/src/main/java/io/api/etherscan/core/IProxyApi.java
@@ -4,11 +4,10 @@
 import io.api.etherscan.model.proxy.BlockProxy;
 import io.api.etherscan.model.proxy.ReceiptProxy;
 import io.api.etherscan.model.proxy.TxProxy;
-import org.jetbrains.annotations.ApiStatus.Experimental;
-import org.jetbrains.annotations.NotNull;
-
 import java.math.BigInteger;
 import java.util.Optional;
+import org.jetbrains.annotations.ApiStatus.Experimental;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan - API Descriptions https://etherscan.io/apis#proxy
diff --git a/src/main/java/io/api/etherscan/core/IStatisticApi.java b/src/main/java/io/api/etherscan/core/IStatisticApi.java
index 1b7ef59..ffd633d 100644
--- a/src/main/java/io/api/etherscan/core/IStatisticApi.java
+++ b/src/main/java/io/api/etherscan/core/IStatisticApi.java
@@ -3,9 +3,8 @@
 import io.api.etherscan.error.ApiException;
 import io.api.etherscan.model.Price;
 import io.api.etherscan.model.Supply;
-import org.jetbrains.annotations.NotNull;
-
 import java.math.BigInteger;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan - API Descriptions https://etherscan.io/apis#stats
diff --git a/src/main/java/io/api/etherscan/core/ITransactionApi.java b/src/main/java/io/api/etherscan/core/ITransactionApi.java
index f545c2d..4180ff4 100644
--- a/src/main/java/io/api/etherscan/core/ITransactionApi.java
+++ b/src/main/java/io/api/etherscan/core/ITransactionApi.java
@@ -2,9 +2,8 @@
 
 import io.api.etherscan.error.ApiException;
 import io.api.etherscan.model.Status;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.Optional;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan - API Descriptions https://etherscan.io/apis#transactions
diff --git a/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java b/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
index 77d8b88..c807598 100644
--- a/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
@@ -8,19 +8,17 @@
 import io.api.etherscan.model.*;
 import io.api.etherscan.model.utility.*;
 import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Account API Implementation
  *
  * @see IAccountApi
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
@@ -148,7 +146,8 @@ public List<Tx> txs(final String address, final long startBlock, final long endB
      * @return List of T values
      */
     private <T, R extends BaseListResponseTO> List<T> getRequestUsingOffset(final String urlParams,
-                                                                            Class<R> tClass) throws ApiException {
+                                                                            Class<R> tClass)
+            throws ApiException {
         final List<T> result = new ArrayList<>();
         int page = 1;
         while (true) {
diff --git a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
index b36f406..ada41bb 100644
--- a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
@@ -9,7 +9,6 @@
 import io.api.etherscan.manager.IQueueManager;
 import io.api.etherscan.model.utility.StringResponseTO;
 import io.api.etherscan.util.BasicUtils;
-
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.Map;
diff --git a/src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java b/src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java
index 9f386a7..d634c9b 100644
--- a/src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java
@@ -7,15 +7,13 @@
 import io.api.etherscan.model.UncleBlock;
 import io.api.etherscan.model.utility.UncleBlockResponseTO;
 import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.Optional;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Block API Implementation
  *
  * @see IBlockApi
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java b/src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java
index 125087f..2e7cbea 100644
--- a/src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java
@@ -14,7 +14,6 @@
  * Contract API Implementation
  *
  * @see IContractApi
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
index ba5dd83..aac428b 100644
--- a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
+++ b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
@@ -10,9 +10,8 @@
 import io.api.etherscan.manager.impl.QueueManager;
 import io.api.etherscan.model.EthNetwork;
 import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.function.Supplier;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan full API Description https://etherscan.io/apis
@@ -85,7 +84,9 @@ public EtherScanApi(final String apiKey,
         // EtherScan 1request\5sec limit support by queue manager
         final IHttpExecutor executor = executorSupplier.get();
 
-        final String ending = EthNetwork.TOBALABA.equals(network) ? "com" : "io";
+        final String ending = EthNetwork.TOBALABA.equals(network)
+                ? "com"
+                : "io";
         final String baseUrl = "https://" + network.getDomain() + ".etherscan." + ending + "/api" + "?apikey=" + apiKey;
 
         this.queueManager = queue;
diff --git a/src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java b/src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java
index 6086869..04f9bb7 100644
--- a/src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java
@@ -8,16 +8,14 @@
 import io.api.etherscan.model.query.impl.LogQuery;
 import io.api.etherscan.model.utility.LogResponseTO;
 import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.Collections;
 import java.util.List;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Logs API Implementation
  *
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java b/src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java
index cb0c6a5..f456186 100644
--- a/src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java
@@ -14,17 +14,15 @@
 import io.api.etherscan.model.proxy.utility.TxInfoProxyTO;
 import io.api.etherscan.model.proxy.utility.TxProxyTO;
 import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.math.BigInteger;
 import java.util.Optional;
 import java.util.regex.Pattern;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Proxy API Implementation
  *
  * @see IProxyApi
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
@@ -109,7 +107,9 @@ public Optional<TxProxy> tx(final String txhash) throws ApiException {
     @Override
     public Optional<TxProxy> tx(final long blockNo, final long index) throws ApiException {
         final long compBlockNo = BasicUtils.compensateMinBlock(blockNo);
-        final long compIndex = (index < 1) ? 1 : index;
+        final long compIndex = (index < 1)
+                ? 1
+                : index;
 
         final String urlParams = ACT_TX_BY_BLOCKNOINDEX_PARAM + TAG_PARAM + compBlockNo + INDEX_PARAM + "0x"
                 + Long.toHexString(compIndex);
diff --git a/src/main/java/io/api/etherscan/core/impl/StatisticApiProvider.java b/src/main/java/io/api/etherscan/core/impl/StatisticApiProvider.java
index d178a81..a14119a 100644
--- a/src/main/java/io/api/etherscan/core/impl/StatisticApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/StatisticApiProvider.java
@@ -10,15 +10,13 @@
 import io.api.etherscan.model.utility.PriceResponseTO;
 import io.api.etherscan.model.utility.StringResponseTO;
 import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.math.BigInteger;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Statistic API Implementation
  *
  * @see IStatisticApi
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/core/impl/TransactionApiProvider.java b/src/main/java/io/api/etherscan/core/impl/TransactionApiProvider.java
index 82eb467..1c83bf0 100644
--- a/src/main/java/io/api/etherscan/core/impl/TransactionApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/TransactionApiProvider.java
@@ -8,9 +8,8 @@
 import io.api.etherscan.model.utility.ReceiptStatusResponseTO;
 import io.api.etherscan.model.utility.StatusResponseTO;
 import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.Optional;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Transaction API Implementation
diff --git a/src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java b/src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java
index 5ba39f2..49e7fee 100644
--- a/src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java
+++ b/src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java
@@ -1,10 +1,11 @@
 package io.api.etherscan.executor.impl;
 
+import static java.net.HttpURLConnection.*;
+
 import io.api.etherscan.error.ApiTimeoutException;
 import io.api.etherscan.error.ConnectionException;
 import io.api.etherscan.executor.IHttpExecutor;
 import io.api.etherscan.util.BasicUtils;
-
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -18,8 +19,6 @@
 import java.util.zip.GZIPInputStream;
 import java.util.zip.InflaterInputStream;
 
-import static java.net.HttpURLConnection.*;
-
 /**
  * Http client implementation
  *
@@ -107,7 +106,9 @@ public String get(final String urlAsString) {
     public String post(final String urlAsString, final String dataToPost) {
         try {
             final HttpURLConnection connection = buildConnection(urlAsString, "POST");
-            final String contentLength = (BasicUtils.isBlank(dataToPost)) ? "0" : String.valueOf(dataToPost.length());
+            final String contentLength = (BasicUtils.isBlank(dataToPost))
+                    ? "0"
+                    : String.valueOf(dataToPost.length());
             connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
             connection.setRequestProperty("Content-Length", contentLength);
             connection.setFixedLengthStreamingMode(dataToPost.length());
diff --git a/src/main/java/io/api/etherscan/manager/impl/QueueManager.java b/src/main/java/io/api/etherscan/manager/impl/QueueManager.java
index 764f7d5..d3a44de 100644
--- a/src/main/java/io/api/etherscan/manager/impl/QueueManager.java
+++ b/src/main/java/io/api/etherscan/manager/impl/QueueManager.java
@@ -1,14 +1,12 @@
 package io.api.etherscan.manager.impl;
 
 import io.api.etherscan.manager.IQueueManager;
-
 import java.util.concurrent.*;
 
 /**
  * Queue Semaphore implementation with size and reset time as params
  * 
  * @see IQueueManager
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/Abi.java b/src/main/java/io/api/etherscan/model/Abi.java
index a48a11d..880e6a0 100644
--- a/src/main/java/io/api/etherscan/model/Abi.java
+++ b/src/main/java/io/api/etherscan/model/Abi.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.util.BasicUtils;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
@@ -49,13 +47,19 @@ public boolean equals(Object o) {
 
         if (isVerified != abi.isVerified)
             return false;
-        return contractAbi != null ? contractAbi.equals(abi.contractAbi) : abi.contractAbi == null;
+        return contractAbi != null
+                ? contractAbi.equals(abi.contractAbi)
+                : abi.contractAbi == null;
     }
 
     @Override
     public int hashCode() {
-        int result = contractAbi != null ? contractAbi.hashCode() : 0;
-        result = 31 * result + (isVerified ? 1 : 0);
+        int result = contractAbi != null
+                ? contractAbi.hashCode()
+                : 0;
+        result = 31 * result + (isVerified
+                ? 1
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/Balance.java b/src/main/java/io/api/etherscan/model/Balance.java
index cbd8502..ed6d6c5 100644
--- a/src/main/java/io/api/etherscan/model/Balance.java
+++ b/src/main/java/io/api/etherscan/model/Balance.java
@@ -1,13 +1,10 @@
 package io.api.etherscan.model;
 
 import io.api.etherscan.model.utility.BalanceTO;
-
 import java.math.BigInteger;
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
@@ -70,7 +67,9 @@ public boolean equals(Object o) {
     @Override
     public int hashCode() {
         int result = balance.hashCode();
-        result = 31 * result + (address != null ? address.hashCode() : 0);
+        result = 31 * result + (address != null
+                ? address.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/BaseTx.java b/src/main/java/io/api/etherscan/model/BaseTx.java
index 6eba826..3942d14 100644
--- a/src/main/java/io/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/api/etherscan/model/BaseTx.java
@@ -2,15 +2,12 @@
 
 import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
@@ -18,7 +15,7 @@ abstract class BaseTx {
 
     private long blockNumber;
     private String timeStamp;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private LocalDateTime _timeStamp;
     private String hash;
     private String from;
@@ -98,11 +95,21 @@ public boolean equals(Object o) {
     @Override
     public int hashCode() {
         int result = (int) (blockNumber ^ (blockNumber >>> 32));
-        result = 31 * result + (timeStamp != null ? timeStamp.hashCode() : 0);
-        result = 31 * result + (hash != null ? hash.hashCode() : 0);
-        result = 31 * result + (from != null ? from.hashCode() : 0);
-        result = 31 * result + (to != null ? to.hashCode() : 0);
-        result = 31 * result + (value != null ? value.hashCode() : 0);
+        result = 31 * result + (timeStamp != null
+                ? timeStamp.hashCode()
+                : 0);
+        result = 31 * result + (hash != null
+                ? hash.hashCode()
+                : 0);
+        result = 31 * result + (from != null
+                ? from.hashCode()
+                : 0);
+        result = 31 * result + (to != null
+                ? to.hashCode()
+                : 0);
+        result = 31 * result + (value != null
+                ? value.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/Block.java b/src/main/java/io/api/etherscan/model/Block.java
index 8853956..f5e8b6a 100644
--- a/src/main/java/io/api/etherscan/model/Block.java
+++ b/src/main/java/io/api/etherscan/model/Block.java
@@ -2,14 +2,11 @@
 
 import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
@@ -18,7 +15,7 @@ public class Block {
     private long blockNumber;
     private BigInteger blockReward;
     private String timeStamp;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private LocalDateTime _timeStamp;
 
     // <editor-fold desc="Getter">
diff --git a/src/main/java/io/api/etherscan/model/EthNetwork.java b/src/main/java/io/api/etherscan/model/EthNetwork.java
index f7b91de..6144cf1 100644
--- a/src/main/java/io/api/etherscan/model/EthNetwork.java
+++ b/src/main/java/io/api/etherscan/model/EthNetwork.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/Log.java b/src/main/java/io/api/etherscan/model/Log.java
index 67ce96f..595122b 100644
--- a/src/main/java/io/api/etherscan/model/Log.java
+++ b/src/main/java/io/api/etherscan/model/Log.java
@@ -2,7 +2,6 @@
 
 import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
@@ -10,34 +9,32 @@
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
 public class Log {
 
     private String blockNumber;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _blockNumber;
     private String address;
     private String transactionHash;
     private String transactionIndex;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _transactionIndex;
     private String timeStamp;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private LocalDateTime _timeStamp;
     private String data;
     private String gasPrice;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private BigInteger _gasPrice;
     private String gasUsed;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private BigInteger _gasUsed;
     private List<String> topics;
     private String logIndex;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _logIndex;
 
     // <editor-fold desc="Getters">
@@ -144,11 +141,21 @@ public boolean equals(Object o) {
 
     @Override
     public int hashCode() {
-        int result = blockNumber != null ? blockNumber.hashCode() : 0;
-        result = 31 * result + (address != null ? address.hashCode() : 0);
-        result = 31 * result + (transactionHash != null ? transactionHash.hashCode() : 0);
-        result = 31 * result + (timeStamp != null ? timeStamp.hashCode() : 0);
-        result = 31 * result + (logIndex != null ? logIndex.hashCode() : 0);
+        int result = blockNumber != null
+                ? blockNumber.hashCode()
+                : 0;
+        result = 31 * result + (address != null
+                ? address.hashCode()
+                : 0);
+        result = 31 * result + (transactionHash != null
+                ? transactionHash.hashCode()
+                : 0);
+        result = 31 * result + (timeStamp != null
+                ? timeStamp.hashCode()
+                : 0);
+        result = 31 * result + (logIndex != null
+                ? logIndex.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/Price.java b/src/main/java/io/api/etherscan/model/Price.java
index 9bc7dc7..fc72ab5 100644
--- a/src/main/java/io/api/etherscan/model/Price.java
+++ b/src/main/java/io/api/etherscan/model/Price.java
@@ -1,13 +1,10 @@
 package io.api.etherscan.model;
 
 import com.google.gson.annotations.Expose;
-
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
@@ -17,9 +14,9 @@ public class Price {
     private double ethbtc;
     private String ethusd_timestamp;
     private String ethbtc_timestamp;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private LocalDateTime _ethusd_timestamp;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private LocalDateTime _ethbtc_timestamp;
 
     public double inUsd() {
@@ -55,9 +52,13 @@ public boolean equals(Object o) {
             return false;
         if (Double.compare(price.ethbtc, ethbtc) != 0)
             return false;
-        if (ethusd_timestamp != null ? !ethusd_timestamp.equals(price.ethusd_timestamp) : price.ethusd_timestamp != null)
+        if (ethusd_timestamp != null
+                ? !ethusd_timestamp.equals(price.ethusd_timestamp)
+                : price.ethusd_timestamp != null)
             return false;
-        return (ethbtc_timestamp != null ? !ethbtc_timestamp.equals(price.ethbtc_timestamp) : price.ethbtc_timestamp != null);
+        return (ethbtc_timestamp != null
+                ? !ethbtc_timestamp.equals(price.ethbtc_timestamp)
+                : price.ethbtc_timestamp != null);
     }
 
     @Override
@@ -68,8 +69,12 @@ public int hashCode() {
         result = (int) (temp ^ (temp >>> 32));
         temp = Double.doubleToLongBits(ethbtc);
         result = 31 * result + (int) (temp ^ (temp >>> 32));
-        result = 31 * result + (ethusd_timestamp != null ? ethusd_timestamp.hashCode() : 0);
-        result = 31 * result + (ethbtc_timestamp != null ? ethbtc_timestamp.hashCode() : 0);
+        result = 31 * result + (ethusd_timestamp != null
+                ? ethusd_timestamp.hashCode()
+                : 0);
+        result = 31 * result + (ethbtc_timestamp != null
+                ? ethbtc_timestamp.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/Status.java b/src/main/java/io/api/etherscan/model/Status.java
index 9683bde..2017cd7 100644
--- a/src/main/java/io/api/etherscan/model/Status.java
+++ b/src/main/java/io/api/etherscan/model/Status.java
@@ -41,7 +41,9 @@ public boolean equals(Object o) {
     @Override
     public int hashCode() {
         int result = isError;
-        result = 31 * result + (errDescription != null ? errDescription.hashCode() : 0);
+        result = 31 * result + (errDescription != null
+                ? errDescription.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/Supply.java b/src/main/java/io/api/etherscan/model/Supply.java
index 2fd6db7..f495aaf 100644
--- a/src/main/java/io/api/etherscan/model/Supply.java
+++ b/src/main/java/io/api/etherscan/model/Supply.java
@@ -3,8 +3,6 @@
 import java.math.BigInteger;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/TokenBalance.java b/src/main/java/io/api/etherscan/model/TokenBalance.java
index d057992..684738c 100644
--- a/src/main/java/io/api/etherscan/model/TokenBalance.java
+++ b/src/main/java/io/api/etherscan/model/TokenBalance.java
@@ -4,8 +4,6 @@
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
@@ -38,7 +36,9 @@ public boolean equals(Object o) {
     @Override
     public int hashCode() {
         int result = super.hashCode();
-        result = 31 * result + (tokenContract != null ? tokenContract.hashCode() : 0);
+        result = 31 * result + (tokenContract != null
+                ? tokenContract.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/Tx.java b/src/main/java/io/api/etherscan/model/Tx.java
index 4136d23..13b5292 100644
--- a/src/main/java/io/api/etherscan/model/Tx.java
+++ b/src/main/java/io/api/etherscan/model/Tx.java
@@ -1,13 +1,10 @@
 package io.api.etherscan.model;
 
 import io.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
@@ -80,9 +77,13 @@ public boolean equals(Object o) {
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + (int) (nonce ^ (nonce >>> 32));
-        result = 31 * result + (blockHash != null ? blockHash.hashCode() : 0);
+        result = 31 * result + (blockHash != null
+                ? blockHash.hashCode()
+                : 0);
         result = 31 * result + transactionIndex;
-        result = 31 * result + (isError != null ? isError.hashCode() : 0);
+        result = 31 * result + (isError != null
+                ? isError.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/TxInternal.java b/src/main/java/io/api/etherscan/model/TxInternal.java
index 5048947..5471268 100644
--- a/src/main/java/io/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/api/etherscan/model/TxInternal.java
@@ -3,8 +3,6 @@
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
@@ -21,7 +19,9 @@ public String getType() {
     }
 
     public long getTraceId() {
-        return (traceId == null) ? 0 : Long.parseLong(traceId);
+        return (traceId == null)
+                ? 0
+                : Long.parseLong(traceId);
     }
 
     public String getTraceIdAsString() {
@@ -56,8 +56,12 @@ public boolean equals(Object o) {
     @Override
     public int hashCode() {
         int result = super.hashCode();
-        result = 31 * result + (traceId != null ? traceId.hashCode() : 0);
-        result = 31 * result + (errCode != null ? errCode.hashCode() : 0);
+        result = 31 * result + (traceId != null
+                ? traceId.hashCode()
+                : 0);
+        result = 31 * result + (errCode != null
+                ? errCode.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/TxToken.java b/src/main/java/io/api/etherscan/model/TxToken.java
index 8f5e36f..c455ffb 100644
--- a/src/main/java/io/api/etherscan/model/TxToken.java
+++ b/src/main/java/io/api/etherscan/model/TxToken.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 28.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/Uncle.java b/src/main/java/io/api/etherscan/model/Uncle.java
index 2ee206b..7dea648 100644
--- a/src/main/java/io/api/etherscan/model/Uncle.java
+++ b/src/main/java/io/api/etherscan/model/Uncle.java
@@ -3,8 +3,6 @@
 import java.math.BigInteger;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
@@ -39,15 +37,23 @@ public boolean equals(Object o) {
 
         if (unclePosition != uncle.unclePosition)
             return false;
-        if (miner != null ? !miner.equals(uncle.miner) : uncle.miner != null)
+        if (miner != null
+                ? !miner.equals(uncle.miner)
+                : uncle.miner != null)
             return false;
-        return blockreward != null ? blockreward.equals(uncle.blockreward) : uncle.blockreward == null;
+        return blockreward != null
+                ? blockreward.equals(uncle.blockreward)
+                : uncle.blockreward == null;
     }
 
     @Override
     public int hashCode() {
-        int result = miner != null ? miner.hashCode() : 0;
-        result = 31 * result + (blockreward != null ? blockreward.hashCode() : 0);
+        int result = miner != null
+                ? miner.hashCode()
+                : 0;
+        result = 31 * result + (blockreward != null
+                ? blockreward.hashCode()
+                : 0);
         result = 31 * result + unclePosition;
         return result;
     }
diff --git a/src/main/java/io/api/etherscan/model/UncleBlock.java b/src/main/java/io/api/etherscan/model/UncleBlock.java
index 88c975d..ff30451 100644
--- a/src/main/java/io/api/etherscan/model/UncleBlock.java
+++ b/src/main/java/io/api/etherscan/model/UncleBlock.java
@@ -1,12 +1,9 @@
 package io.api.etherscan.model;
 
 import io.api.etherscan.util.BasicUtils;
-
 import java.util.List;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/Wei.java b/src/main/java/io/api/etherscan/model/Wei.java
index eddf8d2..0735d90 100644
--- a/src/main/java/io/api/etherscan/model/Wei.java
+++ b/src/main/java/io/api/etherscan/model/Wei.java
@@ -4,8 +4,6 @@
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
@@ -52,7 +50,9 @@ public boolean equals(Object o) {
 
     @Override
     public int hashCode() {
-        return result != null ? result.hashCode() : 0;
+        return result != null
+                ? result.hashCode()
+                : 0;
     }
 
     @Override
diff --git a/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
index 63821c0..2afbe40 100644
--- a/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
@@ -2,33 +2,30 @@
 
 import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.List;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
 public class BlockProxy {
 
     private String number;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _number;
     private String hash;
     private String parentHash;
     private String stateRoot;
     private String size;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _size;
     private String difficulty;
     private String totalDifficulty;
     private String timestamp;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private LocalDateTime _timestamp;
 
     private String miner;
@@ -37,10 +34,10 @@ public class BlockProxy {
     private String logsBloom;
     private String mixHash;
     private String gasUsed;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private BigInteger _gasUsed;
     private String gasLimit;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private BigInteger _gasLimit;
 
     private String sha3Uncles;
@@ -151,18 +148,30 @@ public boolean equals(Object o) {
 
         BlockProxy that = (BlockProxy) o;
 
-        if (number != null ? !number.equals(that.number) : that.number != null)
+        if (number != null
+                ? !number.equals(that.number)
+                : that.number != null)
             return false;
-        if (hash != null ? !hash.equals(that.hash) : that.hash != null)
+        if (hash != null
+                ? !hash.equals(that.hash)
+                : that.hash != null)
             return false;
-        return parentHash != null ? parentHash.equals(that.parentHash) : that.parentHash == null;
+        return parentHash != null
+                ? parentHash.equals(that.parentHash)
+                : that.parentHash == null;
     }
 
     @Override
     public int hashCode() {
-        int result = number != null ? number.hashCode() : 0;
-        result = 31 * result + (hash != null ? hash.hashCode() : 0);
-        result = 31 * result + (parentHash != null ? parentHash.hashCode() : 0);
+        int result = number != null
+                ? number.hashCode()
+                : 0;
+        result = 31 * result + (hash != null
+                ? hash.hashCode()
+                : 0);
+        result = 31 * result + (parentHash != null
+                ? parentHash.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
index f40cb59..1e25dbd 100644
--- a/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
@@ -3,13 +3,10 @@
 import com.google.gson.annotations.Expose;
 import io.api.etherscan.model.Log;
 import io.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 import java.util.List;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
@@ -104,18 +101,30 @@ public boolean equals(Object o) {
 
         ReceiptProxy that = (ReceiptProxy) o;
 
-        if (blockNumber != null ? !blockNumber.equals(that.blockNumber) : that.blockNumber != null)
+        if (blockNumber != null
+                ? !blockNumber.equals(that.blockNumber)
+                : that.blockNumber != null)
             return false;
-        if (transactionHash != null ? !transactionHash.equals(that.transactionHash) : that.transactionHash != null)
+        if (transactionHash != null
+                ? !transactionHash.equals(that.transactionHash)
+                : that.transactionHash != null)
             return false;
-        return transactionIndex != null ? transactionIndex.equals(that.transactionIndex) : that.transactionIndex == null;
+        return transactionIndex != null
+                ? transactionIndex.equals(that.transactionIndex)
+                : that.transactionIndex == null;
     }
 
     @Override
     public int hashCode() {
-        int result = blockNumber != null ? blockNumber.hashCode() : 0;
-        result = 31 * result + (transactionHash != null ? transactionHash.hashCode() : 0);
-        result = 31 * result + (transactionIndex != null ? transactionIndex.hashCode() : 0);
+        int result = blockNumber != null
+                ? blockNumber.hashCode()
+                : 0;
+        result = 31 * result + (transactionHash != null
+                ? transactionHash.hashCode()
+                : 0);
+        result = 31 * result + (transactionIndex != null
+                ? transactionIndex.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/api/etherscan/model/proxy/TxProxy.java
index 5c7b5c8..a89f4a8 100644
--- a/src/main/java/io/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/api/etherscan/model/proxy/TxProxy.java
@@ -2,12 +2,9 @@
 
 import com.google.gson.annotations.Expose;
 import io.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
@@ -16,7 +13,7 @@ public class TxProxy {
     private String to;
     private String hash;
     private String transactionIndex;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _transactionIndex;
     private String from;
     private String v;
@@ -24,18 +21,18 @@ public class TxProxy {
     private String s;
     private String r;
     private String nonce;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _nonce;
     private String value;
     private String gas;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private BigInteger _gas;
     private String gasPrice;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private BigInteger _gasPrice;
     private String blockHash;
     private String blockNumber;
-    @Expose(serialize = false, deserialize = false)
+    @Expose(deserialize = false, serialize = false)
     private Long _blockNumber;
 
     // <editor-fold desc="Getters">
@@ -115,18 +112,30 @@ public boolean equals(Object o) {
 
         TxProxy txProxy = (TxProxy) o;
 
-        if (hash != null ? !hash.equals(txProxy.hash) : txProxy.hash != null)
+        if (hash != null
+                ? !hash.equals(txProxy.hash)
+                : txProxy.hash != null)
             return false;
-        if (blockHash != null ? !blockHash.equals(txProxy.blockHash) : txProxy.blockHash != null)
+        if (blockHash != null
+                ? !blockHash.equals(txProxy.blockHash)
+                : txProxy.blockHash != null)
             return false;
-        return blockNumber != null ? blockNumber.equals(txProxy.blockNumber) : txProxy.blockNumber == null;
+        return blockNumber != null
+                ? blockNumber.equals(txProxy.blockNumber)
+                : txProxy.blockNumber == null;
     }
 
     @Override
     public int hashCode() {
-        int result = hash != null ? hash.hashCode() : 0;
-        result = 31 * result + (blockHash != null ? blockHash.hashCode() : 0);
-        result = 31 * result + (blockNumber != null ? blockNumber.hashCode() : 0);
+        int result = hash != null
+                ? hash.hashCode()
+                : 0;
+        result = 31 * result + (blockHash != null
+                ? blockHash.hashCode()
+                : 0);
+        result = 31 * result + (blockNumber != null
+                ? blockNumber.hashCode()
+                : 0);
         return result;
     }
 
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/BaseProxyTO.java b/src/main/java/io/api/etherscan/model/proxy/utility/BaseProxyTO.java
index 52c886f..0291dfe 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/BaseProxyTO.java
+++ b/src/main/java/io/api/etherscan/model/proxy/utility/BaseProxyTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.proxy.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/BlockProxyTO.java b/src/main/java/io/api/etherscan/model/proxy/utility/BlockProxyTO.java
index eb9d941..2057c89 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/BlockProxyTO.java
+++ b/src/main/java/io/api/etherscan/model/proxy/utility/BlockProxyTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.proxy.BlockProxy;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 01.11.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/ErrorProxyTO.java b/src/main/java/io/api/etherscan/model/proxy/utility/ErrorProxyTO.java
index 57d2c07..a3bc435 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/ErrorProxyTO.java
+++ b/src/main/java/io/api/etherscan/model/proxy/utility/ErrorProxyTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.proxy.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/StringProxyTO.java b/src/main/java/io/api/etherscan/model/proxy/utility/StringProxyTO.java
index 90cd7c8..8d1d08c 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/StringProxyTO.java
+++ b/src/main/java/io/api/etherscan/model/proxy/utility/StringProxyTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.proxy.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/TxInfoProxyTO.java b/src/main/java/io/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
index c709f76..3bbe039 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
+++ b/src/main/java/io/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.proxy.ReceiptProxy;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/TxProxyTO.java b/src/main/java/io/api/etherscan/model/proxy/utility/TxProxyTO.java
index 4140a62..7e9c9e8 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/TxProxyTO.java
+++ b/src/main/java/io/api/etherscan/model/proxy/utility/TxProxyTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.proxy.TxProxy;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 01.11.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/query/impl/BaseLogQuery.java b/src/main/java/io/api/etherscan/model/query/impl/BaseLogQuery.java
index 2fc688a..c472f84 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/BaseLogQuery.java
+++ b/src/main/java/io/api/etherscan/model/query/impl/BaseLogQuery.java
@@ -7,7 +7,6 @@
  *
  * @see LogQueryBuilder
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogQuery.java b/src/main/java/io/api/etherscan/model/query/impl/LogQuery.java
index 3ba6c4f..31d8c13 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogQuery.java
+++ b/src/main/java/io/api/etherscan/model/query/impl/LogQuery.java
@@ -4,12 +4,10 @@
 
 /**
  * Final builded container for The Event Log API
- *
  * EtherScan - API Descriptions https://etherscan.io/apis#logs
  *
  * @see LogQueryBuilder
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java b/src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java
index bd8a9fc..44ca825 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java
+++ b/src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java
@@ -9,7 +9,6 @@
  * Builder for The Event Log API
  *
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicQuadro.java b/src/main/java/io/api/etherscan/model/query/impl/LogTopicQuadro.java
index 1c2bf35..bab5b29 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicQuadro.java
+++ b/src/main/java/io/api/etherscan/model/query/impl/LogTopicQuadro.java
@@ -10,7 +10,6 @@
  *
  * @see LogQueryBuilder
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
@@ -22,8 +21,13 @@ public class LogTopicQuadro extends BaseLogQuery implements IQueryBuilder {
 
     private LogOp topic0_1_opr, topic1_2_opr, topic2_3_opr, topic0_2_opr, topic0_3_opr, topic1_3_opr;
 
-    LogTopicQuadro(String address, long startBlock, long endBlock,
-                   String topic0, String topic1, String topic2, String topic3) {
+    LogTopicQuadro(String address,
+                   long startBlock,
+                   long endBlock,
+                   String topic0,
+                   String topic1,
+                   String topic2,
+                   String topic3) {
         this.address = address;
         this.startBlock = startBlock;
         this.endBlock = endBlock;
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicSingle.java b/src/main/java/io/api/etherscan/model/query/impl/LogTopicSingle.java
index 2c19d61..83199d9 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicSingle.java
+++ b/src/main/java/io/api/etherscan/model/query/impl/LogTopicSingle.java
@@ -9,7 +9,6 @@
  *
  * @see LogQueryBuilder
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTriple.java b/src/main/java/io/api/etherscan/model/query/impl/LogTopicTriple.java
index aa54740..cc9a6ba 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTriple.java
+++ b/src/main/java/io/api/etherscan/model/query/impl/LogTopicTriple.java
@@ -10,7 +10,6 @@
  *
  * @see LogQueryBuilder
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
@@ -22,8 +21,12 @@ public class LogTopicTriple extends BaseLogQuery implements IQueryBuilder {
 
     private LogOp topic0_1_opr, topic1_2_opr, topic0_2_opr;
 
-    LogTopicTriple(String address, long startBlock, long endBlock,
-                   String topic0, String topic1, String topic2) {
+    LogTopicTriple(String address,
+                   long startBlock,
+                   long endBlock,
+                   String topic0,
+                   String topic1,
+                   String topic2) {
         this.address = address;
         this.startBlock = startBlock;
         this.endBlock = endBlock;
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTuple.java b/src/main/java/io/api/etherscan/model/query/impl/LogTopicTuple.java
index 8f069f1..4524a8a 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTuple.java
+++ b/src/main/java/io/api/etherscan/model/query/impl/LogTopicTuple.java
@@ -10,7 +10,6 @@
  *
  * @see LogQueryBuilder
  * @see ILogsApi
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
@@ -22,8 +21,11 @@ public class LogTopicTuple extends BaseLogQuery implements IQueryBuilder {
 
     private LogOp topic0_1_opr;
 
-    LogTopicTuple(String address, long startBlock, long endBlock,
-                  String topic0, String topic1) {
+    LogTopicTuple(String address,
+                  long startBlock,
+                  long endBlock,
+                  String topic0,
+                  String topic1) {
         this.address = address;
         this.startBlock = startBlock;
         this.endBlock = endBlock;
diff --git a/src/main/java/io/api/etherscan/model/utility/BalanceResponseTO.java b/src/main/java/io/api/etherscan/model/utility/BalanceResponseTO.java
index 6b23de4..f7c2985 100644
--- a/src/main/java/io/api/etherscan/model/utility/BalanceResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/BalanceResponseTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/BalanceTO.java b/src/main/java/io/api/etherscan/model/utility/BalanceTO.java
index 8d9d9b7..3956cec 100644
--- a/src/main/java/io/api/etherscan/model/utility/BalanceTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/BalanceTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/BaseListResponseTO.java b/src/main/java/io/api/etherscan/model/utility/BaseListResponseTO.java
index 28f01f3..916739e 100644
--- a/src/main/java/io/api/etherscan/model/utility/BaseListResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/BaseListResponseTO.java
@@ -3,8 +3,6 @@
 import java.util.List;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/BaseResponseTO.java b/src/main/java/io/api/etherscan/model/utility/BaseResponseTO.java
index d3653e2..9679ebb 100644
--- a/src/main/java/io/api/etherscan/model/utility/BaseResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/BaseResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.util.BasicUtils;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
@@ -14,7 +12,9 @@ public abstract class BaseResponseTO {
     private String message;
 
     public int getStatus() {
-        return BasicUtils.isEmpty(status) ? -1 : Integer.parseInt(status);
+        return BasicUtils.isEmpty(status)
+                ? -1
+                : Integer.parseInt(status);
     }
 
     public String getMessage() {
diff --git a/src/main/java/io/api/etherscan/model/utility/BlockParam.java b/src/main/java/io/api/etherscan/model/utility/BlockParam.java
index 0f027ec..7e11a00 100644
--- a/src/main/java/io/api/etherscan/model/utility/BlockParam.java
+++ b/src/main/java/io/api/etherscan/model/utility/BlockParam.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/BlockResponseTO.java b/src/main/java/io/api/etherscan/model/utility/BlockResponseTO.java
index 0d63184..8a89321 100644
--- a/src/main/java/io/api/etherscan/model/utility/BlockResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/BlockResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.Block;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/LogResponseTO.java b/src/main/java/io/api/etherscan/model/utility/LogResponseTO.java
index bba1c24..a060bd3 100644
--- a/src/main/java/io/api/etherscan/model/utility/LogResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/LogResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.Log;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 31.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/PriceResponseTO.java b/src/main/java/io/api/etherscan/model/utility/PriceResponseTO.java
index 3179a73..9af743b 100644
--- a/src/main/java/io/api/etherscan/model/utility/PriceResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/PriceResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.Price;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusResponseTO.java b/src/main/java/io/api/etherscan/model/utility/ReceiptStatusResponseTO.java
index 87e3950..a5f9577 100644
--- a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/ReceiptStatusResponseTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusTO.java b/src/main/java/io/api/etherscan/model/utility/ReceiptStatusTO.java
index 6b7995d..c4c63af 100644
--- a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/ReceiptStatusTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/StatusResponseTO.java b/src/main/java/io/api/etherscan/model/utility/StatusResponseTO.java
index bc10eb7..7532aba 100644
--- a/src/main/java/io/api/etherscan/model/utility/StatusResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/StatusResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.Status;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/StringResponseTO.java b/src/main/java/io/api/etherscan/model/utility/StringResponseTO.java
index 38d3c86..582087a 100644
--- a/src/main/java/io/api/etherscan/model/utility/StringResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/StringResponseTO.java
@@ -1,8 +1,6 @@
 package io.api.etherscan.model.utility;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/TxInternalResponseTO.java b/src/main/java/io/api/etherscan/model/utility/TxInternalResponseTO.java
index d38a879..5f0e400 100644
--- a/src/main/java/io/api/etherscan/model/utility/TxInternalResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/TxInternalResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.TxInternal;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/TxResponseTO.java b/src/main/java/io/api/etherscan/model/utility/TxResponseTO.java
index 53cce38..1fa6b16 100644
--- a/src/main/java/io/api/etherscan/model/utility/TxResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/TxResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.Tx;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java b/src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java
index 5ac2aec..1cbd4e3 100644
--- a/src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.TxToken;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 29.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java b/src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java
index f4f4349..f8e4c5e 100644
--- a/src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java
+++ b/src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java
@@ -3,8 +3,6 @@
 import io.api.etherscan.model.UncleBlock;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 30.10.2018
  */
diff --git a/src/main/java/io/api/etherscan/util/BasicUtils.java b/src/main/java/io/api/etherscan/util/BasicUtils.java
index 96b855d..d748abf 100644
--- a/src/main/java/io/api/etherscan/util/BasicUtils.java
+++ b/src/main/java/io/api/etherscan/util/BasicUtils.java
@@ -5,11 +5,10 @@
 import io.api.etherscan.error.InvalidTxHashException;
 import io.api.etherscan.model.utility.BaseResponseTO;
 import io.api.etherscan.model.utility.BlockParam;
-import org.jetbrains.annotations.NotNull;
-
 import java.math.BigInteger;
 import java.util.*;
 import java.util.regex.Pattern;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Basic utils for library
diff --git a/src/test/java/io/api/ApiRunner.java b/src/test/java/io/api/ApiRunner.java
index 184a84e..e78ea6d 100644
--- a/src/test/java/io/api/ApiRunner.java
+++ b/src/test/java/io/api/ApiRunner.java
@@ -3,10 +3,10 @@
 import io.api.etherscan.core.impl.EtherScanApi;
 import io.api.etherscan.manager.impl.QueueManager;
 import io.api.etherscan.model.EthNetwork;
-import org.junit.AfterClass;
-import org.junit.Assert;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
 
-public class ApiRunner extends Assert {
+public class ApiRunner extends Assertions {
 
     private static final EtherScanApi api;
     private static final EtherScanApi apiRopsten;
@@ -50,7 +50,7 @@ public static EtherScanApi getApiKovan() {
         return apiKovan;
     }
 
-    @AfterClass
+    @AfterAll
     public static void cleanup() throws Exception {
         api.close();
         apiRopsten.close();
diff --git a/src/test/java/io/api/etherscan/EtherScanApiTest.java b/src/test/java/io/api/etherscan/EtherScanApiTest.java
index be49435..b649302 100644
--- a/src/test/java/io/api/etherscan/EtherScanApiTest.java
+++ b/src/test/java/io/api/etherscan/EtherScanApiTest.java
@@ -8,47 +8,43 @@
 import io.api.etherscan.executor.IHttpExecutor;
 import io.api.etherscan.executor.impl.HttpExecutor;
 import io.api.etherscan.model.Balance;
-import io.api.etherscan.model.Block;
 import io.api.etherscan.model.EthNetwork;
-import org.junit.Test;
-
-import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
+import org.junit.jupiter.api.Test;
 
 /**
  * @author GoodforGod
  * @since 05.11.2018
  */
-public class EtherScanApiTest extends ApiRunner {
+class EtherScanApiTest extends ApiRunner {
 
     private final EthNetwork network = EthNetwork.KOVAN;
     private final String validKey = "YourKey";
 
     @Test
-    public void validKey() {
+    void validKey() {
         EtherScanApi api = new EtherScanApi(validKey, network);
         assertNotNull(api);
     }
 
-    @Test(expected = ApiKeyException.class)
-    public void emptyKey() {
-        new EtherScanApi("");
+    @Test
+    void emptyKey() {
+        assertThrows(ApiKeyException.class, () -> new EtherScanApi(""));
     }
 
-    @Test(expected = ApiKeyException.class)
-    public void blankKey() {
-        new EtherScanApi("         ", network);
+    @Test
+    void blankKey() {
+        assertThrows(ApiKeyException.class, () -> new EtherScanApi("         ", network));
     }
 
-    @Test(expected = ApiException.class)
-    public void nullNetwork() {
-        EtherScanApi api = new EtherScanApi(validKey, null);
-        assertNotNull(api);
+    @Test
+    void nullNetwork() {
+        assertThrows(ApiException.class, () -> new EtherScanApi(validKey, null));
     }
 
     @Test
-    public void noTimeoutOnRead() {
+    void noTimeoutOnRead() {
         Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(300);
         EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET, supplier);
         Balance balance = api.account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
@@ -56,31 +52,30 @@ public void noTimeoutOnRead() {
     }
 
     @Test
-    public void noTimeoutOnReadGroli() {
+    void noTimeoutOnReadGroli() {
         Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(300);
         Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
         assertNotNull(balance);
     }
 
     @Test
-    public void noTimeoutOnReadTobalala() {
+    void noTimeoutOnReadTobalala() {
         Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(30000);
         Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
         assertNotNull(balance);
     }
 
     @Test
-    public void noTimeoutUnlimitedAwait() {
+    void noTimeoutUnlimitedAwait() {
         Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
         assertNotNull(balance);
     }
 
-    @Test(expected = ApiTimeoutException.class)
-    public void timeout() throws InterruptedException {
+    @Test
+    void timeout() throws InterruptedException {
         TimeUnit.SECONDS.sleep(5);
         Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(300, 300);
         EtherScanApi api = new EtherScanApi(getApiKey(), EthNetwork.KOVAN, supplier);
-        List<Block> blocks = api.account().minedBlocks("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D");
-        assertNotNull(blocks);
+        assertThrows(ApiTimeoutException.class, () -> api.account().minedBlocks("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D"));
     }
 }
diff --git a/src/test/java/io/api/etherscan/account/AccountBalanceListTest.java b/src/test/java/io/api/etherscan/account/AccountBalanceListTest.java
index fdeb1e9..6864175 100644
--- a/src/test/java/io/api/etherscan/account/AccountBalanceListTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountBalanceListTest.java
@@ -4,22 +4,19 @@
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.Balance;
 import io.api.support.AddressUtil;
-import org.junit.Test;
-
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class AccountBalanceListTest extends ApiRunner {
+class AccountBalanceListTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         List<String> addresses = new ArrayList<>();
         addresses.add("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
         addresses.add("0xC9F32CE1127e44C51cbD182D6364F3D707Fd0d47");
@@ -44,7 +41,7 @@ public void correct() {
     }
 
     @Test
-    public void correctMoreThat20Addresses() {
+    void correctMoreThat20Addresses() {
         List<String> addresses = AddressUtil.genRealAddresses();
 
         List<Balance> balances = getApi().account().balances(addresses);
@@ -58,17 +55,17 @@ public void correctMoreThat20Addresses() {
         assertNotEquals(balances.get(0), balances.get(1));
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
+    @Test
+    void invalidParamWithError() {
         List<String> addresses = new ArrayList<>();
         addresses.add("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
         addresses.add("C9F32CE1127e44C51cbD182D6364F3D707Fd0d47");
 
-        getApi().account().balances(addresses);
+        assertThrows(InvalidAddressException.class, () -> getApi().account().balances(addresses));
     }
 
     @Test
-    public void emptyParamList() {
+    void emptyParamList() {
         List<String> addresses = new ArrayList<>();
         List<Balance> balances = getApi().account().balances(addresses);
         assertNotNull(balances);
@@ -76,7 +73,7 @@ public void emptyParamList() {
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         List<String> addresses = new ArrayList<>();
         addresses.add("0x1327cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
         addresses.add("0xC1F32CE1127e44C51cbD182D6364F3D707Fd0d47");
diff --git a/src/test/java/io/api/etherscan/account/AccountBalanceTest.java b/src/test/java/io/api/etherscan/account/AccountBalanceTest.java
index 76aca68..d5427ab 100644
--- a/src/test/java/io/api/etherscan/account/AccountBalanceTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountBalanceTest.java
@@ -4,50 +4,19 @@
 import io.api.etherscan.core.impl.EtherScanApi;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.Balance;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.Arrays;
-import java.util.Collection;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-@RunWith(Parameterized.class)
-public class AccountBalanceTest extends ApiRunner {
-
-    private final EtherScanApi api;
-    private final String addressCorrect;
-    private final String addressInvalid;
-    private final String addressNoResponse;
-
-    public AccountBalanceTest(EtherScanApi api, String addressCorrect, String addressInvalid, String addressNoResponse) {
-        this.api = api;
-        this.addressCorrect = addressCorrect;
-        this.addressInvalid = addressInvalid;
-        this.addressNoResponse = addressNoResponse;
-    }
+class AccountBalanceTest extends ApiRunner {
 
-    @Parameters
-    public static Collection data() {
-        return Arrays.asList(new Object[][] {
-                {
-                        getApi(),
-                        "0x8d4426f94e42f721C7116E81d6688cd935cB3b4F",
-                        "8d4426f94e42f721C7116E81d6688cd935cB3b4F",
-                        "0x1d4426f94e42f721C7116E81d6688cd935cB3b4F"
-                }
-        });
-    }
+    private final EtherScanApi api = getApi();
 
     @Test
-    public void correct() {
-        Balance balance = api.account().balance(addressCorrect);
+    void correct() {
+        Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
         assertNotNull(balance);
         assertNotNull(balance.getWei());
         assertNotNull(balance.getMwei());
@@ -58,14 +27,14 @@ public void correct() {
         assertNotNull(balance.toString());
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        Balance balance = getApi().account().balance(addressInvalid);
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class, () -> getApi().account().balance("8d4426f94e42f721C7116E81d6688cd935cB3b4F"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
-        Balance balance = api.account().balance(addressNoResponse);
+    void correctParamWithEmptyExpectedResult() {
+        Balance balance = api.account().balance("0x1d4426f94e42f721C7116E81d6688cd935cB3b4F");
         assertNotNull(balance);
         assertNotNull(balance.getWei());
         assertNotNull(balance.getAddress());
diff --git a/src/test/java/io/api/etherscan/account/AccountMinedBlocksTest.java b/src/test/java/io/api/etherscan/account/AccountMinedBlocksTest.java
index 3a46858..ae16174 100644
--- a/src/test/java/io/api/etherscan/account/AccountMinedBlocksTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountMinedBlocksTest.java
@@ -4,61 +4,23 @@
 import io.api.etherscan.core.impl.EtherScanApi;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.Block;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-@RunWith(Parameterized.class)
-public class AccountMinedBlocksTest extends ApiRunner {
-
-    private final EtherScanApi api;
-    private final int blocksMined;
-    private final String addressCorrect;
-    private final String addressInvalid;
-    private final String addressNoResponse;
-
-    public AccountMinedBlocksTest(EtherScanApi api,
-                                  int blocksMined,
-                                  String addressCorrect,
-                                  String addressInvalid,
-                                  String addressNoResponse) {
-        this.api = api;
-        this.blocksMined = blocksMined;
-        this.addressCorrect = addressCorrect;
-        this.addressInvalid = addressInvalid;
-        this.addressNoResponse = addressNoResponse;
-    }
+class AccountMinedBlocksTest extends ApiRunner {
 
-    @Parameters
-    public static Collection data() {
-        return Arrays.asList(new Object[][] {
-                {
-                        getApi(),
-                        223,
-                        "0xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23",
-                        "xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23",
-                        "0xE1C6175183029A0f039bf2DFffa5C6e8F3cA9B23",
-                }
-        });
-    }
+    private final EtherScanApi api = getApi();
 
     @Test
-    public void correct() {
-        List<Block> blocks = api.account().minedBlocks(addressCorrect);
+    void correct() {
+        List<Block> blocks = api.account().minedBlocks("0xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23");
         assertNotNull(blocks);
 
-        assertEquals(blocksMined, blocks.size());
+        assertEquals(223, blocks.size());
         assertBlocks(blocks);
         assertNotNull(blocks.get(0).toString());
 
@@ -68,14 +30,15 @@ public void correct() {
         }
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        List<Block> txs = getApi().account().minedBlocks(addressInvalid);
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class,
+                () -> getApi().account().minedBlocks("xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
-        List<Block> txs = api.account().minedBlocks(addressNoResponse);
+    void correctParamWithEmptyExpectedResult() {
+        List<Block> txs = api.account().minedBlocks("0xE1C6175183029A0f039bf2DFffa5C6e8F3cA9B23");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
     }
diff --git a/src/test/java/io/api/etherscan/account/AccountTokenBalanceTest.java b/src/test/java/io/api/etherscan/account/AccountTokenBalanceTest.java
index 2794e95..b8b8146 100644
--- a/src/test/java/io/api/etherscan/account/AccountTokenBalanceTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTokenBalanceTest.java
@@ -3,63 +3,21 @@
 import io.api.ApiRunner;
 import io.api.etherscan.core.impl.EtherScanApi;
 import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.Balance;
 import io.api.etherscan.model.TokenBalance;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.Arrays;
-import java.util.Collection;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-@RunWith(Parameterized.class)
-public class AccountTokenBalanceTest extends ApiRunner {
-
-    private final EtherScanApi api;
-    private final String contractValid;
-    private final String addressValid;
-    private final String contractInvalid;
-    private final String addressInvalid;
-    private final String addressEmpty;
+class AccountTokenBalanceTest extends ApiRunner {
 
-    public AccountTokenBalanceTest(EtherScanApi api,
-                                   String contractValid,
-                                   String addressValid,
-                                   String contractInvalid,
-                                   String addressInvalid,
-                                   String addressEmpty) {
-        this.api = api;
-        this.contractValid = contractValid;
-        this.addressValid = addressValid;
-        this.contractInvalid = contractInvalid;
-        this.addressInvalid = addressInvalid;
-        this.addressEmpty = addressEmpty;
-    }
-
-    @Parameters
-    public static Collection data() {
-        return Arrays.asList(new Object[][] {
-                {
-                        getApi(),
-                        "0x5EaC95ad5b287cF44E058dCf694419333b796123",
-                        "0x5d807e7F124EC2103a59c5249187f772c0b8D6b2",
-                        "0xEaC95ad5b287cF44E058dCf694419333b796123",
-                        "0x5807e7F124EC2103a59c5249187f772c0b8D6b2",
-                        "0x1d807e7F124EC2103a59c5249187f772c0b8D6b2",
-                }
-        });
-    }
+    private final EtherScanApi api = getApi();
 
     @Test
-    public void correct() {
-        TokenBalance balance = api.account().balance(addressValid, contractValid);
+    void correct() {
+        TokenBalance balance = api.account().balance("0x5d807e7F124EC2103a59c5249187f772c0b8D6b2",
+                "0x5EaC95ad5b287cF44E058dCf694419333b796123");
         assertNotNull(balance);
         assertNotNull(balance.getWei());
         assertNotNull(balance.getAddress());
@@ -71,19 +29,22 @@ public void correct() {
         assertNotEquals(balance.hashCode(), balance2.hashCode());
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidAddressParamWithError() {
-        Balance balance = api.account().balance(addressInvalid, contractValid);
+    @Test
+    void invalidAddressParamWithError() {
+        assertThrows(InvalidAddressException.class, () -> api.account().balance("0x5807e7F124EC2103a59c5249187f772c0b8D6b2",
+                "0x5EaC95ad5b287cF44E058dCf694419333b796123"));
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidContractParamWithError() {
-        Balance balance = api.account().balance(addressValid, contractInvalid);
+    @Test
+    void invalidContractParamWithError() {
+        assertThrows(InvalidAddressException.class, () -> api.account().balance("0x5d807e7F124EC2103a59c5249187f772c0b8D6b2",
+                "0xEaC95ad5b287cF44E058dCf694419333b796123"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
-        TokenBalance balance = api.account().balance(addressEmpty, contractValid);
+    void correctParamWithEmptyExpectedResult() {
+        TokenBalance balance = api.account().balance("0x1d807e7F124EC2103a59c5249187f772c0b8D6b2",
+                "0x5EaC95ad5b287cF44E058dCf694419333b796123");
         assertNotNull(balance);
         assertNotNull(balance.getWei());
         assertNotNull(balance.getAddress());
diff --git a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java b/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
index 126fd90..4e63dbc 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
@@ -5,56 +5,23 @@
 import io.api.etherscan.error.InvalidTxHashException;
 import io.api.etherscan.model.TxInternal;
 import io.api.etherscan.util.BasicUtils;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-@RunWith(Parameterized.class)
-public class AccountTxInternalByHashTest extends ApiRunner {
-
-    private final EtherScanApi api;
-    private final int txAmount;
-    private final String validTx;
-    private final String invalidTx;
-    private final String emptyTx;
-
-    public AccountTxInternalByHashTest(EtherScanApi api, int txAmount, String validTx, String invalidTx, String emptyTx) {
-        this.api = api;
-        this.txAmount = txAmount;
-        this.validTx = validTx;
-        this.invalidTx = invalidTx;
-        this.emptyTx = emptyTx;
-    }
+class AccountTxInternalByHashTest extends ApiRunner {
 
-    @Parameters
-    public static Collection data() {
-        return Arrays.asList(new Object[][] {
-                {
-                        getApi(),
-                        1,
-                        "0x1b513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b",
-                        "0xb513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b",
-                        "0x2b513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b",
-                }
-        });
-    }
+    private final EtherScanApi api = getApi();
 
     @Test
-    public void correct() {
-        List<TxInternal> txs = api.account().txsInternalByHash(validTx);
+    void correct() {
+        List<TxInternal> txs = api.account()
+                .txsInternalByHash("0x1b513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b");
         assertNotNull(txs);
-        assertEquals(txAmount, txs.size());
+        assertEquals(1, txs.size());
         assertTxs(txs);
         assertNotNull(txs.get(0).getFrom());
         assertNotNull(txs.get(0).getTimeStamp());
@@ -73,14 +40,16 @@ public void correct() {
         }
     }
 
-    @Test(expected = InvalidTxHashException.class)
-    public void invalidParamWithError() {
-        List<TxInternal> txs = api.account().txsInternalByHash(invalidTx);
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidTxHashException.class,
+                () -> api.account().txsInternalByHash("0xb513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
-        List<TxInternal> txs = api.account().txsInternalByHash(emptyTx);
+    void correctParamWithEmptyExpectedResult() {
+        List<TxInternal> txs = api.account()
+                .txsInternalByHash("0x2b513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
     }
diff --git a/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java b/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
index 47f3e61..7144671 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
@@ -3,20 +3,17 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.TxInternal;
-import org.junit.Test;
-
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class AccountTxInternalTest extends ApiRunner {
+class AccountTxInternalTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         List<TxInternal> txs = getApi().account().txsInternal("0x2C1ba59D6F58433FB1EaEe7d20b26Ed83bDA51A3");
         assertNotNull(txs);
         assertEquals(66, txs.size());
@@ -25,7 +22,7 @@ public void correct() {
     }
 
     @Test
-    public void correctStartBlock() {
+    void correctStartBlock() {
         List<TxInternal> txs = getApi().account().txsInternal("0x2C1ba59D6F58433FB1EaEe7d20b26Ed83bDA51A3", 2558775);
         assertNotNull(txs);
         assertEquals(24, txs.size());
@@ -35,20 +32,21 @@ public void correctStartBlock() {
     }
 
     @Test
-    public void correctStartBlockEndBlock() {
+    void correctStartBlockEndBlock() {
         List<TxInternal> txs = getApi().account().txsInternal("0x2C1ba59D6F58433FB1EaEe7d20b26Ed83bDA51A3", 2558775, 2685504);
         assertNotNull(txs);
         assertEquals(21, txs.size());
         assertTxs(txs);
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        List<TxInternal> txs = getApi().account().txsInternal("0x2C1ba59D6F58433FB1EaEe7d20b26Ed83bDA51");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class,
+                () -> getApi().account().txsInternal("0x2C1ba59D6F58433FB1EaEe7d20b26Ed83bDA51"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         List<TxInternal> txs = getApi().account().txsInternal("0x2C1ba59D6F58433FB2EaEe7d20b26Ed83bDA51A3");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
diff --git a/src/test/java/io/api/etherscan/account/AccountTxRc721TokenTest.java b/src/test/java/io/api/etherscan/account/AccountTxRc721TokenTest.java
index 0afa12f..6601d1a 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxRc721TokenTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxRc721TokenTest.java
@@ -3,18 +3,17 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.TxToken;
-import org.junit.Test;
-
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
  * @author NGuggs
  * @since 11.28.2021
  */
-public class AccountTxRc721TokenTest extends ApiRunner {
+class AccountTxRc721TokenTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         List<TxToken> txs = getApi().account().txsNftToken("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67");
         assertNotNull(txs);
         assertEquals(16, txs.size());
@@ -33,7 +32,7 @@ public void correct() {
     }
 
     @Test
-    public void correctStartBlock() {
+    void correctStartBlock() {
         List<TxToken> txs = getApi().account().txsNftToken("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4762071);
         System.out.println(txs);
         assertNotNull(txs);
@@ -42,7 +41,7 @@ public void correctStartBlock() {
     }
 
     @Test
-    public void correctStartBlockEndBlock() {
+    void correctStartBlockEndBlock() {
         List<TxToken> txs = getApi().account().txsNftToken("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4761862, 4761934);
         System.out.println(txs);
         assertNotNull(txs);
@@ -50,13 +49,14 @@ public void correctStartBlockEndBlock() {
         assertTxs(txs);
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        getApi().account().txsNftToken("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class,
+                () -> getApi().account().txsNftToken("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         List<TxToken> txs = getApi().account().txsNftToken("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
diff --git a/src/test/java/io/api/etherscan/account/AccountTxTokenTest.java b/src/test/java/io/api/etherscan/account/AccountTxTokenTest.java
index b82d4d1..044991b 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxTokenTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxTokenTest.java
@@ -3,20 +3,17 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.TxToken;
-import org.junit.Test;
-
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class AccountTxTokenTest extends ApiRunner {
+class AccountTxTokenTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         List<TxToken> txs = getApi().account().txsToken("0xE376F69ED2218076682e2b3B7b9099eC50aD68c4");
         assertNotNull(txs);
         assertEquals(3, txs.size());
@@ -35,7 +32,7 @@ public void correct() {
     }
 
     @Test
-    public void correctStartBlock() {
+    void correctStartBlock() {
         List<TxToken> txs = getApi().account().txsToken("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167);
         assertNotNull(txs);
         assertEquals(11, txs.size());
@@ -43,20 +40,21 @@ public void correctStartBlock() {
     }
 
     @Test
-    public void correctStartBlockEndBlock() {
+    void correctStartBlockEndBlock() {
         List<TxToken> txs = getApi().account().txsToken("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167, 5813576);
         assertNotNull(txs);
         assertEquals(5, txs.size());
         assertTxs(txs);
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        getApi().account().txsToken("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class,
+                () -> getApi().account().txsToken("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         List<TxToken> txs = getApi().account().txsToken("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
diff --git a/src/test/java/io/api/etherscan/account/AccountTxsTest.java b/src/test/java/io/api/etherscan/account/AccountTxsTest.java
index 66a95e4..899d0fb 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxsTest.java
+++ b/src/test/java/io/api/etherscan/account/AccountTxsTest.java
@@ -3,20 +3,17 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.Tx;
-import org.junit.Test;
-
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class AccountTxsTest extends ApiRunner {
+class AccountTxsTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         List<Tx> txs = getApi().account().txs("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
         assertNotNull(txs);
         assertEquals(5, txs.size());
@@ -39,7 +36,7 @@ public void correct() {
     }
 
     @Test
-    public void correctStartBlock() {
+    void correctStartBlock() {
         List<Tx> txs = getApi().account().txs("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9", 3892842);
         assertNotNull(txs);
         assertEquals(4, txs.size());
@@ -47,21 +44,21 @@ public void correctStartBlock() {
     }
 
     @Test
-    public void correctStartBlockEndBlock() {
+    void correctStartBlockEndBlock() {
         List<Tx> txs = getApi().account().txs("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9", 3892842, 3945741);
         assertNotNull(txs);
         assertEquals(3, txs.size());
         assertTxs(txs);
-        assertFalse(txs.get(0).equals(txs.get(1)));
+        assertNotEquals(txs.get(0), txs.get(1));
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        List<Tx> txs = getApi().account().txs("9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class, () -> getApi().account().txs("9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         List<Tx> txs = getApi().account().txs("0x9321cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
diff --git a/src/test/java/io/api/etherscan/block/BlockApiTest.java b/src/test/java/io/api/etherscan/block/BlockApiTest.java
index 34b9de5..cee8bb9 100644
--- a/src/test/java/io/api/etherscan/block/BlockApiTest.java
+++ b/src/test/java/io/api/etherscan/block/BlockApiTest.java
@@ -2,20 +2,17 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.model.UncleBlock;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class BlockApiTest extends ApiRunner {
+class BlockApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<UncleBlock> uncle = getApi().block().uncles(2165403);
         assertTrue(uncle.isPresent());
         assertFalse(uncle.get().isEmpty());
@@ -46,14 +43,14 @@ public void correct() {
     }
 
     @Test
-    public void correctNoUncles() {
+    void correctNoUncles() {
         Optional<UncleBlock> uncles = getApi().block().uncles(34);
         assertTrue(uncles.isPresent());
         assertTrue(uncles.get().getUncles().isEmpty());
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<UncleBlock> uncles = getApi().block().uncles(99999999934L);
         assertFalse(uncles.isPresent());
     }
diff --git a/src/test/java/io/api/etherscan/contract/ContractApiTest.java b/src/test/java/io/api/etherscan/contract/ContractApiTest.java
index 6b4d7d8..85fb905 100644
--- a/src/test/java/io/api/etherscan/contract/ContractApiTest.java
+++ b/src/test/java/io/api/etherscan/contract/ContractApiTest.java
@@ -3,18 +3,16 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.model.Abi;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ContractApiTest extends ApiRunner {
+class ContractApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Abi abi = getApi().contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413");
         assertNotNull(abi);
         assertTrue(abi.isVerified());
@@ -27,13 +25,14 @@ public void correct() {
         assertNotEquals(empty.hashCode(), abi.hashCode());
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        getApi().contract().contractAbi("0xBBbc244D798123fDe783fCc1C72d3Bb8C189413");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class,
+                () -> getApi().contract().contractAbi("0xBBbc244D798123fDe783fCc1C72d3Bb8C189413"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Abi abi = getApi().contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413");
         assertNotNull(abi);
         assertTrue(abi.isVerified());
diff --git a/src/test/java/io/api/etherscan/logs/LogQueryBuilderTest.java b/src/test/java/io/api/etherscan/logs/LogQueryBuilderTest.java
index 85b35e8..f956364 100644
--- a/src/test/java/io/api/etherscan/logs/LogQueryBuilderTest.java
+++ b/src/test/java/io/api/etherscan/logs/LogQueryBuilderTest.java
@@ -7,18 +7,16 @@
 import io.api.etherscan.model.query.impl.LogQuery;
 import io.api.etherscan.model.query.impl.LogQueryBuilder;
 import io.api.etherscan.model.query.impl.LogTopicQuadro;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class LogQueryBuilderTest extends ApiRunner {
+class LogQueryBuilderTest extends ApiRunner {
 
     @Test
-    public void singleCorrect() {
+    void singleCorrect() {
         LogQuery single = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .build();
@@ -27,28 +25,22 @@ public void singleCorrect() {
         assertNotNull(single.getParams());
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void singleInCorrectAddress() {
-        LogQuery single = LogQueryBuilder.with("033990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void singleInCorrectAddress() {
+        assertThrows(InvalidAddressException.class, () -> LogQueryBuilder.with("033990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
-                .build();
-
-        assertNotNull(single);
-        assertNotNull(single.getParams());
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void singleInCorrectTopic() {
-        LogQuery single = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void singleInCorrectTopic() {
+        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("6516=")
-                .build();
-
-        assertNotNull(single);
-        assertNotNull(single.getParams());
+                .build());
     }
 
     @Test
-    public void tupleCorrect() {
+    void tupleCorrect() {
         LogQuery tuple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224)
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
@@ -59,20 +51,17 @@ public void tupleCorrect() {
         assertNotNull(tuple.getParams());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void tupleInCorrectOp() {
-        LogQuery tuple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224)
+    @Test
+    void tupleInCorrectOp() {
+        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224)
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                 .setOpTopic0_1(null)
-                .build();
-
-        assertNotNull(tuple);
-        assertNotNull(tuple.getParams());
+                .build());
     }
 
     @Test
-    public void tripleCorrect() {
+    void tripleCorrect() {
         LogQuery triple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -86,68 +75,60 @@ public void tripleCorrect() {
         assertNotNull(triple.getParams());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void tripleInCorrectOp() {
-        LogQuery triple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
-                        "0x72657075746174696f6e00000000000000000000000000000000000000000000",
-                        "0x72657075746174696f6e00000000000000000000000000000000000000000000")
-                .setOpTopic0_1(LogOp.AND)
-                .setOpTopic0_2(null)
-                .setOpTopic1_2(LogOp.AND)
-                .build();
-
-        assertNotNull(triple);
-        assertNotNull(triple.getParams());
+    @Test
+    void tripleInCorrectOp() {
+        assertThrows(LogQueryException.class,
+                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
+                        .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+                                "0x72657075746174696f6e00000000000000000000000000000000000000000000",
+                                "0x72657075746174696f6e00000000000000000000000000000000000000000000")
+                        .setOpTopic0_1(LogOp.AND)
+                        .setOpTopic0_2(null)
+                        .setOpTopic1_2(LogOp.AND)
+                        .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void tripleInCorrectTopic1() {
-        LogQuery triple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                .topic(null,
-                        "0x72657075746174696f6e00000000000000000000000000000000000000000000",
-                        "0x72657075746174696f6e00000000000000000000000000000000000000000000")
-                .setOpTopic0_1(LogOp.AND)
-                .setOpTopic0_2(LogOp.AND)
-                .setOpTopic1_2(LogOp.AND)
-                .build();
-
-        assertNotNull(triple);
-        assertNotNull(triple.getParams());
+    @Test
+    void tripleInCorrectTopic1() {
+        assertThrows(LogQueryException.class,
+                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
+                        .topic(null,
+                                "0x72657075746174696f6e00000000000000000000000000000000000000000000",
+                                "0x72657075746174696f6e00000000000000000000000000000000000000000000")
+                        .setOpTopic0_1(LogOp.AND)
+                        .setOpTopic0_2(LogOp.AND)
+                        .setOpTopic1_2(LogOp.AND)
+                        .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void tripleInCorrectTopic2() {
-        LogQuery triple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
-                        null,
-                        "0x72657075746174696f6e00000000000000000000000000000000000000000000")
-                .setOpTopic0_1(LogOp.AND)
-                .setOpTopic0_2(LogOp.AND)
-                .setOpTopic1_2(LogOp.AND)
-                .build();
-
-        assertNotNull(triple);
-        assertNotNull(triple.getParams());
+    @Test
+    void tripleInCorrectTopic2() {
+        assertThrows(LogQueryException.class,
+                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
+                        .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+                                null,
+                                "0x72657075746174696f6e00000000000000000000000000000000000000000000")
+                        .setOpTopic0_1(LogOp.AND)
+                        .setOpTopic0_2(LogOp.AND)
+                        .setOpTopic1_2(LogOp.AND)
+                        .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void tripleInCorrectTopic3() {
-        LogQuery triple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
-                        "0x72657075746174696f6e00000000000000000000000000000000000000000000",
-                        null)
-                .setOpTopic0_1(LogOp.AND)
-                .setOpTopic0_2(LogOp.AND)
-                .setOpTopic1_2(LogOp.AND)
-                .build();
-
-        assertNotNull(triple);
-        assertNotNull(triple.getParams());
+    @Test
+    void tripleInCorrectTopic3() {
+        assertThrows(LogQueryException.class,
+                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
+                        .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+                                "0x72657075746174696f6e00000000000000000000000000000000000000000000",
+                                null)
+                        .setOpTopic0_1(LogOp.AND)
+                        .setOpTopic0_2(LogOp.AND)
+                        .setOpTopic1_2(LogOp.AND)
+                        .build());
     }
 
     @Test
-    public void quadroCorrect() {
+    void quadroCorrect() {
         LogQuery quadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -165,9 +146,9 @@ public void quadroCorrect() {
         assertNotNull(quadro.getParams());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroIncorrectTopic2() {
-        LogQuery quadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroIncorrectTopic2() {
+        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         null,
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -178,92 +159,83 @@ public void quadroIncorrectTopic2() {
                 .setOpTopic1_2(LogOp.OR)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
-
-        assertNotNull(quadro);
-        assertNotNull(quadro.getParams());
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void tupleIncorrectTopic2() {
-        LogQuery quadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void tupleIncorrectTopic2() {
+        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         null)
                 .setOpTopic0_1(LogOp.AND)
-                .build();
-
-        assertNotNull(quadro);
-        assertNotNull(quadro.getParams());
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void tupleIncorrectTopic1() {
-        LogQuery quadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void tupleIncorrectTopic1() {
+        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic(null,
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .setOpTopic0_1(LogOp.AND)
-                .build();
-
-        assertNotNull(quadro);
-        assertNotNull(quadro.getParams());
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroIncorrectOp1() {
-        LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroIncorrectOp1() {
+        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        topicQuadro
+        assertThrows(LogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(null)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
                 .setOpTopic1_2(LogOp.OR)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroIncorrectOp2() {
-        LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroIncorrectOp2() {
+        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        topicQuadro.setOpTopic0_1(LogOp.AND)
+        assertThrows(LogQueryException.class, () -> topicQuadro.setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(null)
                 .setOpTopic0_3(LogOp.AND)
                 .setOpTopic1_2(LogOp.OR)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroIncorrectOp3() {
-        LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroIncorrectOp3() {
+        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        topicQuadro
+        assertThrows(LogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(null)
                 .setOpTopic1_2(LogOp.OR)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroInCorrectAgainTopic() {
-        LogQuery quadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroInCorrectAgainTopic() {
+        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -274,69 +246,66 @@ public void quadroInCorrectAgainTopic() {
                 .setOpTopic1_2(LogOp.OR)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
-
-        assertNotNull(quadro);
-        assertNotNull(quadro.getParams());
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroInCorrectOp4() {
-        LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroInCorrectOp4() {
+        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        topicQuadro
+        assertThrows(LogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
                 .setOpTopic1_2(null)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroInCorrectOp5() {
-        LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroInCorrectOp5() {
+        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        topicQuadro
+        assertThrows(LogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
                 .setOpTopic1_2(LogOp.AND)
                 .setOpTopic1_3(null)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroInCorrectOp6() {
+    @Test
+    void quadroInCorrectOp6() {
         LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        topicQuadro
+        assertThrows(LogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
                 .setOpTopic1_2(LogOp.AND)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(null)
-                .build();
+                .build());
     }
 
-    @Test(expected = LogQueryException.class)
-    public void quadroInCorrectTopic() {
-        LogQuery quadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
+    @Test
+    void quadroInCorrectTopic() {
+        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "",
@@ -347,9 +316,6 @@ public void quadroInCorrectTopic() {
                 .setOpTopic1_2(LogOp.OR)
                 .setOpTopic1_3(LogOp.OR)
                 .setOpTopic2_3(LogOp.OR)
-                .build();
-
-        assertNotNull(quadro);
-        assertNotNull(quadro.getParams());
+                .build());
     }
 }
diff --git a/src/test/java/io/api/etherscan/logs/LogsApiTest.java b/src/test/java/io/api/etherscan/logs/LogsApiTest.java
index 7143a83..e786e0c 100644
--- a/src/test/java/io/api/etherscan/logs/LogsApiTest.java
+++ b/src/test/java/io/api/etherscan/logs/LogsApiTest.java
@@ -5,34 +5,19 @@
 import io.api.etherscan.model.query.LogOp;
 import io.api.etherscan.model.query.impl.LogQuery;
 import io.api.etherscan.model.query.impl.LogQueryBuilder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-@RunWith(Parameterized.class)
-public class LogsApiTest extends ApiRunner {
-
-    private final LogQuery query;
-    private final int logsSize;
-
-    public LogsApiTest(LogQuery query, int logsSize) {
-        this.query = query;
-        this.logsSize = logsSize;
-    }
+class LogsApiTest extends ApiRunner {
 
-    @Parameters
-    public static Collection data() {
+    static Stream<Arguments> source() {
         LogQuery single = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .build();
@@ -53,16 +38,16 @@ public static Collection data() {
                 .setOpTopic0_1(LogOp.OR)
                 .build();
 
-        return Arrays.asList(new Object[][] {
-                { single, 423 },
-                { singleInvalidAddr, 0 },
-                { tupleAnd, 1 },
-                { tupleOr, 425 }
-        });
+        return Stream.of(
+                Arguments.of(single, 423),
+                Arguments.of(singleInvalidAddr, 0),
+                Arguments.of(tupleAnd, 1),
+                Arguments.of(tupleOr, 425));
     }
 
-    @Test
-    public void validateQuery() {
+    @ParameterizedTest
+    @MethodSource("source")
+    void validateQuery(LogQuery query, int logsSize) {
         List<Log> logs = getApi().logs().logs(query);
         assertEquals(logsSize, logs.size());
 
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
index 5d3884d..faead19 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
@@ -5,27 +5,24 @@
 import io.api.etherscan.manager.impl.QueueManager;
 import io.api.etherscan.model.EthNetwork;
 import io.api.etherscan.model.proxy.BlockProxy;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyBlockApiTest extends ApiRunner {
+class ProxyBlockApiTest extends ApiRunner {
 
     private final EtherScanApi api;
 
-    public ProxyBlockApiTest() {
+    ProxyBlockApiTest() {
         final QueueManager queueManager = new QueueManager(1, 5100L, 5100L, 0);
         this.api = new EtherScanApi(getApiKey(), EthNetwork.MAINNET, queueManager);
     }
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<BlockProxy> block = api.proxy().block(5120);
         assertTrue(block.isPresent());
         BlockProxy proxy = block.get();
@@ -58,13 +55,13 @@ public void correct() {
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<BlockProxy> block = api.proxy().block(99999999999L);
         assertFalse(block.isPresent());
     }
 
     @Test
-    public void correctParamNegativeNo() {
+    void correctParamNegativeNo() {
         Optional<BlockProxy> block = api.proxy().block(-1);
         assertTrue(block.isPresent());
         assertNotNull(block.get().getHash());
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyBlockLastNoApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
index 5485391..f866b6a 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
@@ -1,18 +1,16 @@
 package io.api.etherscan.proxy;
 
 import io.api.ApiRunner;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 13.11.2018
  */
-public class ProxyBlockLastNoApiTest extends ApiRunner {
+class ProxyBlockLastNoApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         long noLast = getApi().proxy().blockNoLast();
         assertNotEquals(0, noLast);
     }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyBlockUncleApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyBlockUncleApiTest.java
index 474c5bb..67a8875 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyBlockUncleApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyBlockUncleApiTest.java
@@ -2,20 +2,17 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.model.proxy.BlockProxy;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 13.11.2018
  */
-public class ProxyBlockUncleApiTest extends ApiRunner {
+class ProxyBlockUncleApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<BlockProxy> block = getApi().proxy().blockUncle(603183, 0);
         assertTrue(block.isPresent());
         assertNotNull(block.get().getHash());
@@ -23,13 +20,13 @@ public void correct() {
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<BlockProxy> block = getApi().proxy().blockUncle(5120, 1);
         assertFalse(block.isPresent());
     }
 
     @Test
-    public void correctParamNegativeNo() {
+    void correctParamNegativeNo() {
         Optional<BlockProxy> block = getApi().proxy().blockUncle(-603183, 0);
         assertFalse(block.isPresent());
     }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
index 07d26bd..8cf46c9 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
@@ -4,43 +4,40 @@
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.error.InvalidDataHexException;
 import io.api.etherscan.util.BasicUtils;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyCallApiTest extends ApiRunner {
+class ProxyCallApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<String> call = getApi().proxy().call("0xAEEF46DB4855E25702F8237E8f403FddcaF931C0",
                 "0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724");
         assertTrue(call.isPresent());
         assertFalse(BasicUtils.isNotHex(call.get()));
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        Optional<String> call = getApi().proxy().call("0xEEF46DB4855E25702F8237E8f403FddcaF931C0",
-                "0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class, () -> getApi().proxy().call("0xEEF46DB4855E25702F8237E8f403FddcaF931C0",
+                "0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724"));
     }
 
-    @Test(expected = InvalidDataHexException.class)
-    public void invalidParamNotHex() {
-        Optional<String> call = getApi().proxy().call("0xAEEF46DB4855E25702F8237E8f403FddcaF931C0",
-                "7-0a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724");
+    @Test
+    void invalidParamNotHex() {
+        assertThrows(InvalidDataHexException.class, () -> getApi().proxy().call("0xAEEF46DB4855E25702F8237E8f403FddcaF931C0",
+                "7-0a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<String> call = getApi().proxy().call("0xAEEF16DB4855E25702F8237E8f403FddcaF931C0",
                 "0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724");
         assertTrue(call.isPresent());
-        assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
+        assertFalse(BasicUtils.isNotHex(call.get()), call.get());
     }
 }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java
index 9e4910c..6835f07 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java
@@ -3,34 +3,31 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
 import io.api.etherscan.util.BasicUtils;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyCodeApiTest extends ApiRunner {
+class ProxyCodeApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<String> call = getApi().proxy().code("0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c");
         assertTrue(call.isPresent());
-        assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
+        assertFalse(BasicUtils.isNotHex(call.get()), call.get());
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class, () -> getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<String> call = getApi().proxy().code("0xf15e354c5edc8efed9b59ee9f67a80845ade7d0c");
         assertTrue(call.isPresent());
-        assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
+        assertFalse(BasicUtils.isNotHex(call.get()), call.get());
     }
 }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyGasApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyGasApiTest.java
index 63e476c..b4b6f37 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyGasApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyGasApiTest.java
@@ -2,34 +2,31 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidDataHexException;
-import org.junit.Test;
-
 import java.math.BigInteger;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyGasApiTest extends ApiRunner {
+class ProxyGasApiTest extends ApiRunner {
 
     @Test
-    public void correctPrice() {
+    void correctPrice() {
         BigInteger price = getApi().proxy().gasPrice();
         assertNotNull(price);
         assertNotEquals(0, price.intValue());
     }
 
     @Test
-    public void correctEstimated() {
+    void correctEstimated() {
         BigInteger price = getApi().proxy().gasEstimated();
         assertNotNull(price);
         assertNotEquals(0, price.intValue());
     }
 
     @Test
-    public void correctEstimatedWithData() {
+    void correctEstimatedWithData() {
         String dataCustom = "606060405260728060106000396000f360606040526000606060405260728060106000396000f360606040526000";
         BigInteger price = getApi().proxy().gasEstimated();
         BigInteger priceCustom = getApi().proxy().gasEstimated(dataCustom);
@@ -38,9 +35,9 @@ public void correctEstimatedWithData() {
         assertNotEquals(price, priceCustom);
     }
 
-    @Test(expected = InvalidDataHexException.class)
-    public void invalidParamWithError() {
+    @Test
+    void invalidParamWithError() {
         String dataCustom = "280&60106000396000f360606040526000";
-        BigInteger priceCustom = getApi().proxy().gasEstimated(dataCustom);
+        assertThrows(InvalidDataHexException.class, () -> getApi().proxy().gasEstimated(dataCustom));
     }
 }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
index 19945e2..6d2e8e4 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
@@ -2,31 +2,29 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyStorageApiTest extends ApiRunner {
+class ProxyStorageApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<String> call = getApi().proxy().storageAt("0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0);
         assertFalse(call.isPresent());
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        getApi().proxy().storageAt("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0);
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class,
+                () -> getApi().proxy().storageAt("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         final Optional<String> call = getApi().proxy().storageAt("0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 10000);
         assertFalse(call.isPresent());
     }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyTxApiTest.java
index 2779120..decf95f 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyTxApiTest.java
@@ -3,20 +3,17 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidTxHashException;
 import io.api.etherscan.model.proxy.TxProxy;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyTxApiTest extends ApiRunner {
+class ProxyTxApiTest extends ApiRunner {
 
     @Test
-    public void correctByHash() {
+    void correctByHash() {
         Optional<TxProxy> tx = getApi().proxy().tx("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
         assertTrue(tx.isPresent());
         assertNotNull(tx.get().getBlockHash());
@@ -33,7 +30,7 @@ public void correctByHash() {
     }
 
     @Test
-    public void correctByBlockNo() {
+    void correctByBlockNo() {
         Optional<TxProxy> tx = getApi().proxy().tx(637368, 0);
         assertTrue(tx.isPresent());
         assertNotNull(tx.get().getBlockHash());
@@ -52,19 +49,20 @@ public void correctByBlockNo() {
         assertNotNull(tx.get().getInput());
     }
 
-    @Test(expected = InvalidTxHashException.class)
-    public void invalidParamWithError() {
-        Optional<TxProxy> tx = getApi().proxy().tx("0xe2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidTxHashException.class,
+                () -> getApi().proxy().tx("0xe2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResultBlockNoExist() {
+    void correctParamWithEmptyExpectedResultBlockNoExist() {
         Optional<TxProxy> tx = getApi().proxy().tx(99999999L, 0);
         assertFalse(tx.isPresent());
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<TxProxy> tx = getApi().proxy().tx("0x2e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
         assertFalse(tx.isPresent());
     }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
index b81926f..0083f7a 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
@@ -2,41 +2,40 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyTxCountApiTest extends ApiRunner {
+class ProxyTxCountApiTest extends ApiRunner {
 
     @Test
-    public void correctSended() {
+    void correctSended() {
         int count = getApi().proxy().txSendCount("0x2910543af39aba0cd09dbb2d50200b3e800a63d2");
         assertNotEquals(0, count);
     }
 
     @Test
-    public void correctByBlockNo() {
+    void correctByBlockNo() {
         int count = getApi().proxy().txCount(6137420);
         assertNotEquals(0, count);
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        int count = getApi().proxy().txSendCount("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class,
+                () -> getApi().proxy().txSendCount("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResultBlockNoExist() {
+    void correctParamWithEmptyExpectedResultBlockNoExist() {
         int count = getApi().proxy().txCount(99999999999L);
         assertNotEquals(1, count);
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         int count = getApi().proxy().txSendCount("0x1e03d9cce9d60f3e9f2597e13cd4c54c55330cfd");
         assertNotEquals(1, count);
     }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxReceiptApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyTxReceiptApiTest.java
index c4a3383..0159ed9 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxReceiptApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyTxReceiptApiTest.java
@@ -3,20 +3,17 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidTxHashException;
 import io.api.etherscan.model.proxy.ReceiptProxy;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class ProxyTxReceiptApiTest extends ApiRunner {
+class ProxyTxReceiptApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<ReceiptProxy> infoProxy = getApi().proxy()
                 .txReceipt("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
         assertTrue(infoProxy.isPresent());
@@ -40,14 +37,14 @@ public void correct() {
         assertNotEquals(empty.hashCode(), infoProxy.get().hashCode());
     }
 
-    @Test(expected = InvalidTxHashException.class)
-    public void invalidParamWithError() {
-        Optional<ReceiptProxy> infoProxy = getApi().proxy()
-                .txReceipt("0xe2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidTxHashException.class, () -> getApi().proxy()
+                .txReceipt("0xe2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<ReceiptProxy> infoProxy = getApi().proxy()
                 .txReceipt("0x2e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
         assertFalse(infoProxy.isPresent());
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxSendRawApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyTxSendRawApiTest.java
index 40e79a6..676dc3a 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxSendRawApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyTxSendRawApiTest.java
@@ -3,36 +3,33 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.EtherScanException;
 import io.api.etherscan.error.InvalidDataHexException;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
 // TODO contact etherscan and ask about method behavior
-public class ProxyTxSendRawApiTest extends ApiRunner {
+class ProxyTxSendRawApiTest extends ApiRunner {
 
-    public void correct() {
+    void correct() {
         Optional<String> sendRaw = getApi().proxy()
                 .txSendRaw("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
         assertTrue(sendRaw.isPresent());
     }
 
-    @Test(expected = InvalidDataHexException.class)
-    public void invalidParamWithError() {
-        Optional<String> sendRaw = getApi().proxy().txSendRaw("5151=0561");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidDataHexException.class, () -> getApi().proxy().txSendRaw("5151=0561"));
     }
 
-    @Test(expected = EtherScanException.class)
-    public void invalidParamEtherScanDataException() {
-        Optional<String> sendRaw = getApi().proxy().txSendRaw("0x1");
+    @Test
+    void invalidParamEtherScanDataException() {
+        assertThrows(EtherScanException.class, () -> getApi().proxy().txSendRaw("0x1"));
     }
 
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<String> sendRaw = getApi().proxy().txSendRaw("0x000000");
         assertFalse(sendRaw.isPresent());
     }
diff --git a/src/test/java/io/api/etherscan/statistic/StatisticPriceApiTest.java b/src/test/java/io/api/etherscan/statistic/StatisticPriceApiTest.java
index e29a6b1..9f89738 100644
--- a/src/test/java/io/api/etherscan/statistic/StatisticPriceApiTest.java
+++ b/src/test/java/io/api/etherscan/statistic/StatisticPriceApiTest.java
@@ -2,18 +2,16 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.model.Price;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class StatisticPriceApiTest extends ApiRunner {
+class StatisticPriceApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Price price = getApi().stats().lastPrice();
         assertNotNull(price);
         assertNotNull(price.btcTimestamp());
diff --git a/src/test/java/io/api/etherscan/statistic/StatisticSupplyApiTest.java b/src/test/java/io/api/etherscan/statistic/StatisticSupplyApiTest.java
index a705a31..32c3018 100644
--- a/src/test/java/io/api/etherscan/statistic/StatisticSupplyApiTest.java
+++ b/src/test/java/io/api/etherscan/statistic/StatisticSupplyApiTest.java
@@ -2,20 +2,17 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.model.Supply;
-import org.junit.Test;
-
 import java.math.BigInteger;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class StatisticSupplyApiTest extends ApiRunner {
+class StatisticSupplyApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Supply supply = getApi().stats().supply();
         assertNotNull(supply);
         assertNotNull(supply.getValue());
diff --git a/src/test/java/io/api/etherscan/statistic/StatisticTokenSupplyApiTest.java b/src/test/java/io/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
index 0a84d01..aefb2bd 100644
--- a/src/test/java/io/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
+++ b/src/test/java/io/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
@@ -2,32 +2,29 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidAddressException;
-import org.junit.Test;
-
 import java.math.BigInteger;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class StatisticTokenSupplyApiTest extends ApiRunner {
+class StatisticTokenSupplyApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         BigInteger supply = getApi().stats().supply("0x57d90b64a1a57749b0f932f1a3395792e12e7055");
         assertNotNull(supply);
         assertNotEquals(BigInteger.ZERO, supply);
     }
 
-    @Test(expected = InvalidAddressException.class)
-    public void invalidParamWithError() {
-        BigInteger supply = getApi().stats().supply("0x7d90b64a1a57749b0f932f1a3395792e12e7055");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidAddressException.class, () -> getApi().stats().supply("0x7d90b64a1a57749b0f932f1a3395792e12e7055"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         BigInteger supply = getApi().stats().supply("0x51d90b64a1a57749b0f932f1a3395792e12e7055");
         assertNotNull(supply);
         assertEquals(0, supply.intValue());
diff --git a/src/test/java/io/api/etherscan/transaction/TransactionExecApiTest.java b/src/test/java/io/api/etherscan/transaction/TransactionExecApiTest.java
index 25320cc..de67a02 100644
--- a/src/test/java/io/api/etherscan/transaction/TransactionExecApiTest.java
+++ b/src/test/java/io/api/etherscan/transaction/TransactionExecApiTest.java
@@ -3,20 +3,17 @@
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidTxHashException;
 import io.api.etherscan.model.Status;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class TransactionExecApiTest extends ApiRunner {
+class TransactionExecApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<Status> status = getApi().txs().execStatus("0x15f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a");
         assertTrue(status.isPresent());
         assertTrue(status.get().haveError());
@@ -28,13 +25,14 @@ public void correct() {
         assertNotEquals(empty.hashCode(), status.get().hashCode());
     }
 
-    @Test(expected = InvalidTxHashException.class)
-    public void invalidParamWithError() {
-        getApi().txs().execStatus("0xb513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidTxHashException.class,
+                () -> getApi().txs().execStatus("0xb513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<Status> status = getApi().txs().execStatus("0x55f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a");
         assertTrue(status.isPresent());
         assertFalse(status.get().haveError());
diff --git a/src/test/java/io/api/etherscan/transaction/TransactionReceiptApiTest.java b/src/test/java/io/api/etherscan/transaction/TransactionReceiptApiTest.java
index a459355..94b93b3 100644
--- a/src/test/java/io/api/etherscan/transaction/TransactionReceiptApiTest.java
+++ b/src/test/java/io/api/etherscan/transaction/TransactionReceiptApiTest.java
@@ -2,33 +2,31 @@
 
 import io.api.ApiRunner;
 import io.api.etherscan.error.InvalidTxHashException;
-import org.junit.Test;
-
 import java.util.Optional;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class TransactionReceiptApiTest extends ApiRunner {
+class TransactionReceiptApiTest extends ApiRunner {
 
     @Test
-    public void correct() {
+    void correct() {
         Optional<Boolean> status = getApi().txs()
                 .receiptStatus("0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
         assertTrue(status.isPresent());
         assertTrue(status.get());
     }
 
-    @Test(expected = InvalidTxHashException.class)
-    public void invalidParamWithError() {
-        getApi().txs().receiptStatus("0x13c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
+    @Test
+    void invalidParamWithError() {
+        assertThrows(InvalidTxHashException.class,
+                () -> getApi().txs().receiptStatus("0x13c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76"));
     }
 
     @Test
-    public void correctParamWithEmptyExpectedResult() {
+    void correctParamWithEmptyExpectedResult() {
         Optional<Boolean> status = getApi().txs()
                 .receiptStatus("0x113c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
         assertFalse(status.isPresent());
diff --git a/src/test/java/io/api/manager/QueueManagerTest.java b/src/test/java/io/api/manager/QueueManagerTest.java
index 74e674c..7bd53a9 100644
--- a/src/test/java/io/api/manager/QueueManagerTest.java
+++ b/src/test/java/io/api/manager/QueueManagerTest.java
@@ -4,18 +4,17 @@
 import io.api.etherscan.manager.IQueueManager;
 import io.api.etherscan.manager.impl.FakeQueueManager;
 import io.api.etherscan.manager.impl.QueueManager;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class QueueManagerTest extends ApiRunner {
+class QueueManagerTest extends ApiRunner {
 
     @Test
-    public void fakeManager() {
+    void fakeManager() {
         IQueueManager fakeManager = new FakeQueueManager();
         fakeManager.takeTurn();
         fakeManager.takeTurn();
@@ -26,16 +25,18 @@ public void fakeManager() {
         assertNotNull(fakeManager);
     }
 
-    @Test(timeout = 3500)
-    public void queueManager() {
+    @Test
+    @Timeout(3500)
+    void queueManager() {
         IQueueManager queueManager = new QueueManager(1, 3);
         queueManager.takeTurn();
         queueManager.takeTurn();
         assertNotNull(queueManager);
     }
 
-    @Test(timeout = 4500)
-    public void queueManagerWithDelay() {
+    @Test
+    @Timeout(4500)
+    void queueManagerWithDelay() {
         IQueueManager queueManager = new QueueManager(1, 2, 2);
         queueManager.takeTurn();
         queueManager.takeTurn();
@@ -43,7 +44,7 @@ public void queueManagerWithDelay() {
     }
 
     @Test
-    public void queueManagerTimeout() {
+    void queueManagerTimeout() {
         IQueueManager queueManager = new QueueManager(1, 3);
         queueManager.takeTurn();
         long start = System.currentTimeMillis();
diff --git a/src/test/java/io/api/support/AddressUtil.java b/src/test/java/io/api/support/AddressUtil.java
index 7949b9e..da04c37 100644
--- a/src/test/java/io/api/support/AddressUtil.java
+++ b/src/test/java/io/api/support/AddressUtil.java
@@ -5,14 +5,12 @@
 import java.util.concurrent.ThreadLocalRandom;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 03.11.2018
  */
 public class AddressUtil {
 
-    public static List<String> genFakeAddresses(int size) {
+    static List<String> genFakeAddresses(int size) {
         final List<String> addresses = new ArrayList<>();
         for (int i = 0; i < size; i++)
             addresses.add("0x9327cb34984c" + ThreadLocalRandom.current().nextInt(1000, 9999) + "ec1EA0eAE98Ccf80A74f95B9");
diff --git a/src/test/java/io/api/util/BasicUtilsTests.java b/src/test/java/io/api/util/BasicUtilsTests.java
index c35bada..36c22cb 100644
--- a/src/test/java/io/api/util/BasicUtilsTests.java
+++ b/src/test/java/io/api/util/BasicUtilsTests.java
@@ -1,103 +1,88 @@
 package io.api.util;
 
+import static io.api.etherscan.util.BasicUtils.*;
+
 import com.google.gson.Gson;
 import io.api.ApiRunner;
 import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.error.ParseException;
 import io.api.etherscan.model.utility.StringResponseTO;
-import org.junit.Test;
-
 import java.util.ArrayList;
 import java.util.List;
-
-import static io.api.etherscan.util.BasicUtils.*;
+import org.junit.jupiter.api.Test;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author GoodforGod
  * @since 13.11.2018
  */
-public class BasicUtilsTests extends ApiRunner {
+class BasicUtilsTests extends ApiRunner {
 
-    @Test(expected = EtherScanException.class)
-    public void responseValidateEmpty() {
+    @Test
+    void responseValidateEmpty() {
         String response = "{\"status\":\"0\",\"message\":\"No ether\",\"result\":\"status\"}";
         StringResponseTO responseTO = new Gson().fromJson(response, StringResponseTO.class);
-        validateTxResponse(responseTO);
+
+        assertThrows(EtherScanException.class, () -> validateTxResponse(responseTO));
     }
 
     @Test
-    public void partitionEmpty() {
+    void partitionEmpty() {
         ArrayList<String> list = new ArrayList<>();
         List<List<String>> lists = partition(list, 12);
         assertTrue(lists.isEmpty());
     }
 
     @Test
-    public void partitionNullParam() {
+    void partitionNullParam() {
         List<List<String>> lists = partition(null, 12);
         assertTrue(lists.isEmpty());
     }
 
     @Test
-    public void isBlankNull() {
+    void isBlankNull() {
         boolean result = isBlank(null);
         assertTrue(result);
     }
 
     @Test
-    public void isEmptyCollectionNull() {
-        List<String> list = null;
-        boolean result = isEmpty(list);
-        assertTrue(result);
-    }
-
-    @Test
-    public void isEmptyCollectionEmpty() {
+    void isEmptyCollectionEmpty() {
         ArrayList<Object> list = new ArrayList<>();
         boolean result = isEmpty(list);
         assertTrue(result);
     }
 
     @Test
-    public void isNotAddressNull() {
+    void isNotAddressNull() {
         boolean result = isNotAddress("");
         assertTrue(result);
     }
 
     @Test
-    public void isNotHexNull() {
+    void isNotHexNull() {
         boolean result = isNotHex("");
         assertTrue(result);
     }
 
     @Test
-    public void isNotAddressInvalid() {
+    void isNotAddressInvalid() {
         boolean result = isNotAddress("125125");
         assertTrue(result);
     }
 
     @Test
-    public void isNotHexInvalid() {
+    void isNotHexInvalid() {
         boolean result = isNotHex("1215%");
         assertTrue(result);
     }
 
-    @Test(expected = EtherScanException.class)
-    public void isResponseStatusInvalidThrows() {
+    @Test
+    void isResponseStatusInvalidThrows() {
         StringResponseTO responseTO = new StringResponseTO();
-        validateTxResponse(responseTO);
+        assertThrows(EtherScanException.class, () -> validateTxResponse(responseTO));
     }
 
-    @Test(expected = EtherScanException.class)
-    public void isResponseNullThrows() {
+    @Test
+    void isResponseNullThrows() {
         StringResponseTO responseTO = null;
-        validateTxResponse(responseTO);
-    }
-
-    @Test(expected = ParseException.class)
-    public void isThrowParseException() {
-        throw new ParseException("Test", null, null);
+        assertThrows(EtherScanException.class, () -> validateTxResponse(responseTO));
     }
 }

From 1559a3faf723dbc0d9bba75b1e7ab4a764f262b6 Mon Sep 17 00:00:00 2001
From: Abhay Gupta <abhay@coinflow.com>
Date: Thu, 21 Jul 2022 13:31:07 +0530
Subject: [PATCH 08/67] added support for txsToken with contract address too

---
 .../io/api/etherscan/core/IAccountApi.java    | 19 ++++++++++++++
 .../core/impl/AccountApiProvider.java         | 26 +++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/src/main/java/io/api/etherscan/core/IAccountApi.java b/src/main/java/io/api/etherscan/core/IAccountApi.java
index 25254aa..b3e12fb 100644
--- a/src/main/java/io/api/etherscan/core/IAccountApi.java
+++ b/src/main/java/io/api/etherscan/core/IAccountApi.java
@@ -110,6 +110,25 @@ public interface IAccountApi {
     @NotNull
     List<TxToken> txsToken(String address) throws ApiException;
 
+    /**
+     * All ERC-20 token txs for given address and contract address
+     *
+     * @param address    get txs for
+     * @param contractAddress contract address to get txs for
+     * @param startBlock tx from this blockNumber
+     * @param endBlock   tx to this blockNumber
+     * @return txs for address
+     * @throws ApiException parent exception class
+     */
+    @NotNull
+    List<TxToken> txsToken(String address, String contractAddress, long startBlock, long endBlock) throws ApiException;
+
+    @NotNull
+    List<TxToken> txsToken(String address, String contractAddress, long startBlock) throws ApiException;
+
+    @NotNull
+    List<TxToken> txsToken(String address, String contractAddress) throws ApiException;
+
     /**
      * All ERC-721 (NFT) token txs for given address
      *
diff --git a/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java b/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
index 77d8b88..dba413a 100644
--- a/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
@@ -230,6 +230,32 @@ public List<TxToken> txsToken(final String address, final long startBlock, final
         return getRequestUsingOffset(urlParams, TxTokenResponseTO.class);
     }
 
+    @NotNull
+    @Override
+    public List<TxToken> txsToken(final String address, final String contractAddress) throws ApiException {
+        return txsToken(address, contractAddress, MIN_START_BLOCK);
+    }
+
+    @NotNull
+    @Override
+    public List<TxToken> txsToken(final String address, final String contractAddress, final long startBlock) throws ApiException {
+        return txsToken(address, contractAddress, startBlock, MAX_END_BLOCK);
+    }
+
+    @NotNull
+    @Override
+    public List<TxToken> txsToken(final String address, final String contractAddress, final long startBlock, final long endBlock) throws ApiException {
+        BasicUtils.validateAddress(address);
+        final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
+
+        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
+        final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
+        final String urlParams = ACT_TX_TOKEN_ACTION + offsetParam + ADDRESS_PARAM + address
+                + CONTRACT_PARAM + contractAddress + blockParam + SORT_ASC_PARAM;
+
+        return getRequestUsingOffset(urlParams, TxTokenResponseTO.class);
+    }
+
     @NotNull
     @Override
     public List<TxToken> txsNftToken(String address) throws ApiException {

From 9fb7d918e63deaf349bbd09b5635935db995f4cd Mon Sep 17 00:00:00 2001
From: Abhay Gupta <abhay@coinflow.com>
Date: Mon, 14 Nov 2022 17:59:49 +0530
Subject: [PATCH 09/67] gas tracker API implementation

---
 .../io/api/etherscan/core/IGasTrackerApi.java | 23 +++++++
 .../api/etherscan/core/impl/EtherScanApi.java |  7 ++
 .../core/impl/GasTrackerApiProvider.java      | 39 +++++++++++
 .../io/api/etherscan/model/GasOracle.java     | 68 +++++++++++++++++++
 .../model/utility/GasOracleResponseTO.java    | 18 +++++
 5 files changed, 155 insertions(+)
 create mode 100644 src/main/java/io/api/etherscan/core/IGasTrackerApi.java
 create mode 100644 src/main/java/io/api/etherscan/core/impl/GasTrackerApiProvider.java
 create mode 100644 src/main/java/io/api/etherscan/model/GasOracle.java
 create mode 100644 src/main/java/io/api/etherscan/model/utility/GasOracleResponseTO.java

diff --git a/src/main/java/io/api/etherscan/core/IGasTrackerApi.java b/src/main/java/io/api/etherscan/core/IGasTrackerApi.java
new file mode 100644
index 0000000..894713f
--- /dev/null
+++ b/src/main/java/io/api/etherscan/core/IGasTrackerApi.java
@@ -0,0 +1,23 @@
+package io.api.etherscan.core;
+
+import io.api.etherscan.error.ApiException;
+import io.api.etherscan.model.GasOracle;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan - API Descriptions https://docs.etherscan.io/api-endpoints/gas-tracker
+ *
+ * @author Abhay Gupta
+ * @since 14.11.2022
+ */
+public interface IGasTrackerApi {
+
+    /**
+     * GasOracle details
+     *
+     * @return fast, suggested gas price
+     * @throws ApiException parent exception class
+     */
+    @NotNull
+    GasOracle gasoracle() throws ApiException;
+}
diff --git a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
index ba5dd83..957315d 100644
--- a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
+++ b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
@@ -34,6 +34,7 @@ public class EtherScanApi implements AutoCloseable {
     private final IProxyApi proxy;
     private final IStatisticApi stats;
     private final ITransactionApi txs;
+    private final IGasTrackerApi gastracker;
 
     public EtherScanApi() {
         this(DEFAULT_KEY, EthNetwork.MAINNET);
@@ -96,6 +97,7 @@ public EtherScanApi(final String apiKey,
         this.proxy = new ProxyApiProvider(queue, baseUrl, executor);
         this.stats = new StatisticApiProvider(queue, baseUrl, executor);
         this.txs = new TransactionApiProvider(queue, baseUrl, executor);
+        this.gastracker = new GasTrackerApiProvider(queue, baseUrl, executor);
     }
 
     @NotNull
@@ -133,6 +135,11 @@ public IStatisticApi stats() {
         return stats;
     }
 
+    @NotNull
+    public IGasTrackerApi gastracker() {
+        return gastracker;
+    }
+
     @Override
     public void close() throws Exception {
         queueManager.close();
diff --git a/src/main/java/io/api/etherscan/core/impl/GasTrackerApiProvider.java b/src/main/java/io/api/etherscan/core/impl/GasTrackerApiProvider.java
new file mode 100644
index 0000000..16d2e63
--- /dev/null
+++ b/src/main/java/io/api/etherscan/core/impl/GasTrackerApiProvider.java
@@ -0,0 +1,39 @@
+package io.api.etherscan.core.impl;
+
+import io.api.etherscan.core.IGasTrackerApi;
+import io.api.etherscan.error.ApiException;
+import io.api.etherscan.error.EtherScanException;
+import io.api.etherscan.executor.IHttpExecutor;
+import io.api.etherscan.manager.IQueueManager;
+import io.api.etherscan.model.GasOracle;
+import io.api.etherscan.model.utility.GasOracleResponseTO;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * GasTracker API Implementation
+ *
+ * @see IGasTrackerApi
+ *
+ * @author Abhay Gupta
+ * @since 14.11.2022
+ */
+public class GasTrackerApiProvider extends BasicProvider implements IGasTrackerApi {
+
+    private static final String ACT_GAS_ORACLE_PARAM = ACT_PREFIX + "gasoracle";
+
+    GasTrackerApiProvider(final IQueueManager queue,
+                          final String baseUrl,
+                          final IHttpExecutor executor) {
+        super(queue, "gastracker", baseUrl, executor);
+    }
+
+    @NotNull
+    @Override
+    public GasOracle gasoracle() throws ApiException {
+        final GasOracleResponseTO response = getRequest(ACT_GAS_ORACLE_PARAM, GasOracleResponseTO.class);
+        if (response.getStatus() != 1)
+            throw new EtherScanException(response);
+
+        return response.getResult();
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/GasOracle.java b/src/main/java/io/api/etherscan/model/GasOracle.java
new file mode 100644
index 0000000..f3f66c2
--- /dev/null
+++ b/src/main/java/io/api/etherscan/model/GasOracle.java
@@ -0,0 +1,68 @@
+package io.api.etherscan.model;
+
+import java.math.BigInteger;
+import java.util.Objects;
+
+/**
+ * ! NO DESCRIPTION !
+ *
+ * @author Abhay Gupta
+ * @since 14.11.2022
+ */
+public class GasOracle {
+    private Long LastBlock;
+    private Integer SafeGasPrice;
+    private Integer ProposeGasPrice;
+    private Integer FastGasPrice;
+    private Double suggestBaseFee;
+    private String gasUsedRatio;
+
+    public Long getLastBlock() {
+        return LastBlock;
+    }
+
+    public BigInteger getSafeGasPriceInWei() {
+        return BigInteger.valueOf(SafeGasPrice).multiply(BigInteger.TEN.pow(9));
+    }
+
+    public BigInteger getProposeGasPriceInWei() {
+        return BigInteger.valueOf(ProposeGasPrice).multiply(BigInteger.TEN.pow(9));
+    }
+
+    public BigInteger getFastGasPriceInWei() {
+        return BigInteger.valueOf(FastGasPrice).multiply(BigInteger.TEN.pow(9));
+    }
+
+    public Double getSuggestBaseFee() {
+        return suggestBaseFee;
+    }
+
+    public String getGasUsedRatio() {
+        return gasUsedRatio;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        GasOracle gasOracle = (GasOracle) o;
+        return LastBlock.equals(gasOracle.LastBlock) && SafeGasPrice.equals(gasOracle.SafeGasPrice) && ProposeGasPrice.equals(gasOracle.ProposeGasPrice) && FastGasPrice.equals(gasOracle.FastGasPrice) && suggestBaseFee.equals(gasOracle.suggestBaseFee) && gasUsedRatio.equals(gasOracle.gasUsedRatio);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(LastBlock, SafeGasPrice, ProposeGasPrice, FastGasPrice, suggestBaseFee, gasUsedRatio);
+    }
+
+    @Override
+    public String toString() {
+        return "GasOracle{" +
+                "LastBlock=" + LastBlock +
+                ", SafeGasPrice=" + SafeGasPrice +
+                ", ProposeGasPrice=" + ProposeGasPrice +
+                ", FastGasPrice=" + FastGasPrice +
+                ", suggestBaseFee=" + suggestBaseFee +
+                ", gasUsedRatio='" + gasUsedRatio + '\'' +
+                '}';
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/utility/GasOracleResponseTO.java b/src/main/java/io/api/etherscan/model/utility/GasOracleResponseTO.java
new file mode 100644
index 0000000..f0c1fd5
--- /dev/null
+++ b/src/main/java/io/api/etherscan/model/utility/GasOracleResponseTO.java
@@ -0,0 +1,18 @@
+package io.api.etherscan.model.utility;
+
+import io.api.etherscan.model.GasOracle;
+
+/**
+ * ! NO DESCRIPTION !
+ *
+ * @author Abhay Gupta
+ * @since 14.11.2022
+ */
+public class GasOracleResponseTO extends BaseResponseTO {
+
+    private GasOracle result;
+
+    public GasOracle getResult() {
+        return result;
+    }
+}

From 2174387cf8c57e86e4303b5468a258e017c257e6 Mon Sep 17 00:00:00 2001
From: Abhay Gupta <abhay@coinflow.com>
Date: Mon, 14 Nov 2022 18:11:34 +0530
Subject: [PATCH 10/67] debug url

---
 src/main/java/io/api/etherscan/core/impl/BasicProvider.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
index b36f406..b0fbe68 100644
--- a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
@@ -77,6 +77,7 @@ <T> T convert(final String json, final Class<T> tClass) {
     String getRequest(final String urlParameters) {
         queue.takeTurn();
         final String url = baseUrl + module + urlParameters;
+        System.out.println("Url generated: " + url);
         final String result = executor.get(url);
         if (BasicUtils.isEmpty(result))
             throw new EtherScanException("Server returned null value for GET request at URL - " + url);

From bf59b713daddb826c01d292b900f4ce6a462b184 Mon Sep 17 00:00:00 2001
From: Abhay Gupta <abhay@coinflow.com>
Date: Mon, 14 Nov 2022 19:01:50 +0530
Subject: [PATCH 11/67] fixed gas oracle base url

---
 src/main/java/io/api/etherscan/core/impl/EtherScanApi.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
index 957315d..028c52b 100644
--- a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
+++ b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
@@ -88,6 +88,7 @@ public EtherScanApi(final String apiKey,
 
         final String ending = EthNetwork.TOBALABA.equals(network) ? "com" : "io";
         final String baseUrl = "https://" + network.getDomain() + ".etherscan." + ending + "/api" + "?apikey=" + apiKey;
+        final String mainnetBaseUrl = "https://" + EthNetwork.MAINNET.getDomain() + ".etherscan." + ending + "/api" + "?apikey=" + apiKey;
 
         this.queueManager = queue;
         this.account = new AccountApiProvider(queue, baseUrl, executor);
@@ -97,7 +98,7 @@ public EtherScanApi(final String apiKey,
         this.proxy = new ProxyApiProvider(queue, baseUrl, executor);
         this.stats = new StatisticApiProvider(queue, baseUrl, executor);
         this.txs = new TransactionApiProvider(queue, baseUrl, executor);
-        this.gastracker = new GasTrackerApiProvider(queue, baseUrl, executor);
+        this.gastracker = new GasTrackerApiProvider(queue, mainnetBaseUrl, executor);
     }
 
     @NotNull

From c462175c09a35d15e0c7641e77e2cbeb5e0e892b Mon Sep 17 00:00:00 2001
From: Abhay Gupta <abhay@coinflow.com>
Date: Mon, 14 Nov 2022 19:04:10 +0530
Subject: [PATCH 12/67] removed sout

---
 src/main/java/io/api/etherscan/core/impl/BasicProvider.java | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
index b0fbe68..b36f406 100644
--- a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
+++ b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
@@ -77,7 +77,6 @@ <T> T convert(final String json, final Class<T> tClass) {
     String getRequest(final String urlParameters) {
         queue.takeTurn();
         final String url = baseUrl + module + urlParameters;
-        System.out.println("Url generated: " + url);
         final String result = executor.get(url);
         if (BasicUtils.isEmpty(result))
             throw new EtherScanException("Server returned null value for GET request at URL - " + url);

From f3d6858f1633e7523bf759f7bd18039872f48a0b Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Thu, 11 May 2023 23:53:28 +0300
Subject: [PATCH 13/67] [2.0.0-SNAPSHOT] Package refactoring API refactoring
 Contracts renamed LogQuery refactored EtherScanAPI refactored & builder added

---
 .github/workflows/gradle.yml                  |   2 +-
 README.md                                     |   5 +-
 build.gradle                                  |  13 +-
 gradle/wrapper/gradle-wrapper.properties      |   2 +-
 .../java/io/api/etherscan/core/IBlockApi.java |  25 ----
 .../io/api/etherscan/core/IContractApi.java   |  24 ---
 .../java/io/api/etherscan/core/ILogsApi.java  |  27 ----
 .../io/api/etherscan/core/IStatisticApi.java  |  44 ------
 .../etherscan/core/impl/BasicProvider.java    |  99 ------------
 .../core/impl/ContractApiProvider.java        |  46 ------
 .../api/etherscan/core/impl/EtherScanApi.java | 141 ------------------
 .../etherscan/core/impl/LogsApiProvider.java  |  43 ------
 .../io/api/etherscan/error/ApiException.java  |  16 --
 .../api/etherscan/error/ApiKeyException.java  |  12 --
 .../etherscan/error/ApiTimeoutException.java  |  12 --
 .../etherscan/error/ConnectionException.java  |  16 --
 .../etherscan/error/EtherScanException.java   |  23 ---
 .../etherscan/error/EventModelException.java  |  12 --
 .../error/InvalidAddressException.java        |  12 --
 .../error/InvalidDataHexException.java        |  12 --
 .../error/InvalidTxHashException.java         |  12 --
 .../etherscan/error/LogQueryException.java    |  12 --
 .../etherscan/error/RateLimitException.java   |  12 --
 .../api/etherscan/manager/IQueueManager.java  |  16 --
 .../etherscan/manager/impl/QueueManager.java  |  62 --------
 .../io/api/etherscan/model/EthNetwork.java    |  25 ----
 .../java/io/api/etherscan/model/Uncle.java    |  69 ---------
 .../io/api/etherscan/model/UncleBlock.java    |  65 --------
 .../etherscan/model/query/IQueryBuilder.java  |  15 --
 .../etherscan/model/query/impl/LogQuery.java  |  28 ----
 .../model/query/impl/LogQueryBuilder.java     |  83 -----------
 .../model/utility/TxTokenResponseTO.java      |  11 --
 .../model/utility/UncleBlockResponseTO.java   |  16 --
 .../api/etherscan/AccountAPI.java}            |  62 ++++----
 .../api/etherscan/AccountAPIProvider.java}    | 122 +++++++--------
 .../api/etherscan/BasicProvider.java          |  93 ++++++++++++
 .../io/goodforgod/api/etherscan/BlockAPI.java |  25 ++++
 .../api/etherscan/BlockAPIProvider.java}      |  29 ++--
 .../goodforgod/api/etherscan/ContractAPI.java |  24 +++
 .../api/etherscan/ContractAPIProvider.java    |  45 ++++++
 .../goodforgod/api/etherscan/EthNetwork.java  |  14 ++
 .../goodforgod/api/etherscan/EthNetworks.java |  29 ++++
 .../api/etherscan/EthScanAPIBuilder.java      |  71 +++++++++
 .../api/etherscan/EtherScanAPI.java           |  61 ++++++++
 .../api/etherscan/EtherScanAPIProvider.java   |  89 +++++++++++
 .../io/goodforgod/api/etherscan/LogsAPI.java  |  27 ++++
 .../api/etherscan/LogsAPIProvider.java        |  42 ++++++
 .../api/etherscan/ProxyAPI.java}              |  70 ++++-----
 .../api/etherscan/ProxyAPIProvider.java}      |  77 +++++-----
 .../api/etherscan/StatisticAPI.java           |  44 ++++++
 .../api/etherscan/StatisticAPIProvider.java}  |  41 +++--
 .../api/etherscan/TransactionAPI.java}        |  18 +--
 .../etherscan/TransactionAPIProvider.java}    |  33 ++--
 .../error/ErtherScanLogQueryException.java    |  12 ++
 .../error/EtherScanConnectionException.java   |  16 ++
 .../etherscan/error/EtherScanException.java   |  16 ++
 .../EtherScanInvalidAddressException.java     |  12 ++
 .../EtherScanInvalidDataHexException.java     |  12 ++
 .../EtherScanInvalidTxHashException.java      |  12 ++
 .../error/EtherScanKeyException.java          |  12 ++
 .../error/EtherScanParseException.java}       |   6 +-
 .../error/EtherScanRateLimitException.java    |  12 ++
 .../error/EtherScanResponseException.java     |  23 +++
 .../error/EtherScanTimeoutException.java      |  12 ++
 .../etherscan/executor/EthHttpClient.java}    |   4 +-
 .../executor/impl/UrlEthHttpClient.java}      |  64 ++++----
 .../manager/RequestQueueManager.java          |  24 +++
 .../impl/FakeRequestQueueManager.java}        |   6 +-
 .../impl/SemaphoreRequestQueueManager.java    |  53 +++++++
 .../api/etherscan/model/Abi.java              |   4 +-
 .../api/etherscan/model/Balance.java          |   4 +-
 .../api/etherscan/model/BaseTx.java           |   4 +-
 .../api/etherscan/model/Block.java            |   4 +-
 .../api/etherscan/model/BlockUncle.java       | 128 ++++++++++++++++
 .../api/etherscan/model/Log.java              |   4 +-
 .../api/etherscan/model/Price.java            |   2 +-
 .../api/etherscan/model/Status.java           |   2 +-
 .../api/etherscan/model/Supply.java           |   2 +-
 .../api/etherscan/model/TokenBalance.java     |   2 +-
 .../api/etherscan/model/Tx.java               |   4 +-
 .../api/etherscan/model/TxERC20.java}         |   6 +-
 .../api/etherscan/model/TxERC721.java         |  71 +++++++++
 .../api/etherscan/model/TxInternal.java       |   2 +-
 .../api/etherscan/model/Wei.java              |   2 +-
 .../api/etherscan/model/proxy/BlockProxy.java |   4 +-
 .../etherscan/model/proxy/ReceiptProxy.java   |   6 +-
 .../api/etherscan/model/proxy/TxProxy.java    |   4 +-
 .../model/proxy/utility/BaseProxyTO.java      |   2 +-
 .../model/proxy/utility/BlockProxyTO.java     |   4 +-
 .../model/proxy/utility/ErrorProxyTO.java     |   2 +-
 .../model/proxy/utility/StringProxyTO.java    |   2 +-
 .../model/proxy/utility/TxInfoProxyTO.java    |   4 +-
 .../model/proxy/utility/TxProxyTO.java        |   4 +-
 .../api/etherscan/model/query/LogOp.java      |   2 +-
 .../api/etherscan/model/query/LogQuery.java   |  51 +++++++
 .../model/query/LogQueryBuilderImpl.java      |  84 +++++++++++
 .../etherscan/model/query/LogQueryImpl.java   |  30 ++++
 .../model/query/LogQueryParams.java}          |  12 +-
 .../model/query/LogTopicBuilder.java          |  17 +++
 .../model/query}/LogTopicQuadro.java          |  33 ++--
 .../model/query}/LogTopicSingle.java          |  20 +--
 .../model/query}/LogTopicTriple.java          |  27 ++--
 .../etherscan/model/query}/LogTopicTuple.java |  23 +--
 .../model/response}/BalanceResponseTO.java    |   2 +-
 .../etherscan/model/response}/BalanceTO.java  |   2 +-
 .../model/response}/BaseListResponseTO.java   |   2 +-
 .../model/response}/BaseResponseTO.java       |   4 +-
 .../etherscan/model/response}/BlockParam.java |   2 +-
 .../model/response}/BlockResponseTO.java      |   4 +-
 .../model/response}/LogResponseTO.java        |   4 +-
 .../model/response}/PriceResponseTO.java      |   4 +-
 .../response}/ReceiptStatusResponseTO.java    |   2 +-
 .../model/response}/ReceiptStatusTO.java      |   2 +-
 .../model/response}/StatusResponseTO.java     |   4 +-
 .../model/response}/StringResponseTO.java     |   2 +-
 .../model/response/TxERC20ResponseTO.java     |  11 ++
 .../model/response/TxERC721ResponseTO.java    |  11 ++
 .../model/response}/TxInternalResponseTO.java |   4 +-
 .../model/response}/TxResponseTO.java         |   4 +-
 .../model/response/UncleBlockResponseTO.java  |  16 ++
 .../api/etherscan/util/BasicUtils.java        |  32 ++--
 src/test/java/io/api/ApiRunner.java           |  60 --------
 .../io/api/etherscan/EtherScanApiTest.java    |  81 ----------
 .../java/io/api/manager/QueueManagerTest.java |  55 -------
 .../goodforgod/api/etherscan/ApiRunner.java   |  66 ++++++++
 .../api/etherscan/EtherScanAPITests.java      |  76 ++++++++++
 .../account/AccountBalanceListTest.java       |  12 +-
 .../etherscan/account/AccountBalanceTest.java |  15 +-
 .../account/AccountMinedBlocksTest.java       |  20 +--
 .../account/AccountTokenBalanceTest.java      |  22 +--
 .../account/AccountTxERC20Test.java}          |  26 ++--
 .../account/AccountTxInternalByHashTest.java  |  16 +-
 .../account/AccountTxInternalTest.java        |  10 +-
 .../account/AccountTxRc721TokenTest.java      |  26 ++--
 .../api/etherscan/account/AccountTxsTest.java |  11 +-
 .../api/etherscan/block/BlockApiTest.java     |  14 +-
 .../etherscan/contract/ContractApiTest.java   |  10 +-
 .../etherscan/logs/LogQueryBuilderTest.java   | 141 +++++++++---------
 .../api/etherscan/logs/LogsApiTest.java       |  27 ++--
 .../SemaphoreRequestQueueManagerTest.java     |  56 +++++++
 .../etherscan/proxy/ProxyBlockApiTest.java    |  19 +--
 .../proxy/ProxyBlockLastNoApiTest.java        |   4 +-
 .../proxy/ProxyBlockUncleApiTest.java         |   6 +-
 .../api/etherscan/proxy/ProxyCallApiTest.java |  20 +--
 .../api/etherscan/proxy/ProxyCodeApiTest.java |  11 +-
 .../api/etherscan/proxy/ProxyGasApiTest.java  |   8 +-
 .../etherscan/proxy/ProxyStorageApiTest.java  |   8 +-
 .../api/etherscan/proxy/ProxyTxApiTest.java   |  10 +-
 .../etherscan/proxy/ProxyTxCountApiTest.java  |   8 +-
 .../proxy/ProxyTxReceiptApiTest.java          |  10 +-
 .../proxy/ProxyTxSendRawApiTest.java          |  12 +-
 .../statistic/StatisticPriceApiTest.java      |   6 +-
 .../statistic/StatisticSupplyApiTest.java     |   6 +-
 .../StatisticTokenSupplyApiTest.java          |   9 +-
 .../api/etherscan}/support/AddressUtil.java   |   2 +-
 .../transaction/TransactionExecApiTest.java   |  16 +-
 .../TransactionReceiptApiTest.java            |  14 +-
 .../api/etherscan}/util/BasicUtilsTests.java  |  16 +-
 158 files changed, 2083 insertions(+), 1854 deletions(-)
 delete mode 100644 src/main/java/io/api/etherscan/core/IBlockApi.java
 delete mode 100644 src/main/java/io/api/etherscan/core/IContractApi.java
 delete mode 100644 src/main/java/io/api/etherscan/core/ILogsApi.java
 delete mode 100644 src/main/java/io/api/etherscan/core/IStatisticApi.java
 delete mode 100644 src/main/java/io/api/etherscan/core/impl/BasicProvider.java
 delete mode 100644 src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java
 delete mode 100644 src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
 delete mode 100644 src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java
 delete mode 100644 src/main/java/io/api/etherscan/error/ApiException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/ApiKeyException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/ApiTimeoutException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/ConnectionException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/EtherScanException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/EventModelException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/InvalidAddressException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/InvalidDataHexException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/InvalidTxHashException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/LogQueryException.java
 delete mode 100644 src/main/java/io/api/etherscan/error/RateLimitException.java
 delete mode 100644 src/main/java/io/api/etherscan/manager/IQueueManager.java
 delete mode 100644 src/main/java/io/api/etherscan/manager/impl/QueueManager.java
 delete mode 100644 src/main/java/io/api/etherscan/model/EthNetwork.java
 delete mode 100644 src/main/java/io/api/etherscan/model/Uncle.java
 delete mode 100644 src/main/java/io/api/etherscan/model/UncleBlock.java
 delete mode 100644 src/main/java/io/api/etherscan/model/query/IQueryBuilder.java
 delete mode 100644 src/main/java/io/api/etherscan/model/query/impl/LogQuery.java
 delete mode 100644 src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java
 delete mode 100644 src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java
 delete mode 100644 src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java
 rename src/main/java/io/{api/etherscan/core/IAccountApi.java => goodforgod/api/etherscan/AccountAPI.java} (55%)
 rename src/main/java/io/{api/etherscan/core/impl/AccountApiProvider.java => goodforgod/api/etherscan/AccountAPIProvider.java} (59%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/BlockAPI.java
 rename src/main/java/io/{api/etherscan/core/impl/BlockApiProvider.java => goodforgod/api/etherscan/BlockAPIProvider.java} (53%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/EthNetwork.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/EthNetworks.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
 rename src/main/java/io/{api/etherscan/core/IProxyApi.java => goodforgod/api/etherscan/ProxyAPI.java} (63%)
 rename src/main/java/io/{api/etherscan/core/impl/ProxyApiProvider.java => goodforgod/api/etherscan/ProxyAPIProvider.java} (75%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
 rename src/main/java/io/{api/etherscan/core/impl/StatisticApiProvider.java => goodforgod/api/etherscan/StatisticAPIProvider.java} (54%)
 rename src/main/java/io/{api/etherscan/core/ITransactionApi.java => goodforgod/api/etherscan/TransactionAPI.java} (51%)
 rename src/main/java/io/{api/etherscan/core/impl/TransactionApiProvider.java => goodforgod/api/etherscan/TransactionAPIProvider.java} (60%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/ErtherScanLogQueryException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidAddressException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidDataHexException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidTxHashException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanKeyException.java
 rename src/main/java/io/{api/etherscan/error/ParseException.java => goodforgod/api/etherscan/error/EtherScanParseException.java} (52%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanRateLimitException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java
 rename src/main/java/io/{api/etherscan/executor/IHttpExecutor.java => goodforgod/api/etherscan/executor/EthHttpClient.java} (84%)
 rename src/main/java/io/{api/etherscan/executor/impl/HttpExecutor.java => goodforgod/api/etherscan/executor/impl/UrlEthHttpClient.java} (66%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
 rename src/main/java/io/{api/etherscan/manager/impl/FakeQueueManager.java => goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java} (65%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Abi.java (94%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Balance.java (94%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/BaseTx.java (97%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Block.java (94%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Log.java (98%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Price.java (98%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Status.java (96%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Supply.java (81%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/TokenBalance.java (96%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Tx.java (96%)
 rename src/main/java/io/{api/etherscan/model/TxToken.java => goodforgod/api/etherscan/model/TxERC20.java} (93%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/TxInternal.java (97%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/Wei.java (96%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/BlockProxy.java (98%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/ReceiptProxy.java (96%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/TxProxy.java (97%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/utility/BaseProxyTO.java (86%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/utility/BlockProxyTO.java (63%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/utility/ErrorProxyTO.java (81%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/utility/StringProxyTO.java (77%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/utility/TxInfoProxyTO.java (63%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/proxy/utility/TxProxyTO.java (62%)
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/query/LogOp.java (86%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
 rename src/main/java/io/{api/etherscan/model/query/impl/BaseLogQuery.java => goodforgod/api/etherscan/model/query/LogQueryParams.java} (79%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicBuilder.java
 rename src/main/java/io/{api/etherscan/model/query/impl => goodforgod/api/etherscan/model/query}/LogTopicQuadro.java (71%)
 rename src/main/java/io/{api/etherscan/model/query/impl => goodforgod/api/etherscan/model/query}/LogTopicSingle.java (53%)
 rename src/main/java/io/{api/etherscan/model/query/impl => goodforgod/api/etherscan/model/query}/LogTopicTriple.java (68%)
 rename src/main/java/io/{api/etherscan/model/query/impl => goodforgod/api/etherscan/model/query}/LogTopicTuple.java (63%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/BalanceResponseTO.java (70%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/BalanceTO.java (83%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/BaseListResponseTO.java (82%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/BaseResponseTO.java (77%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/BlockParam.java (88%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/BlockResponseTO.java (54%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/LogResponseTO.java (54%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/PriceResponseTO.java (66%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/ReceiptStatusResponseTO.java (81%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/ReceiptStatusTO.java (77%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/StatusResponseTO.java (66%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/StringResponseTO.java (79%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/TxInternalResponseTO.java (55%)
 rename src/main/java/io/{api/etherscan/model/utility => goodforgod/api/etherscan/model/response}/TxResponseTO.java (54%)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/UncleBlockResponseTO.java
 rename src/main/java/io/{ => goodforgod}/api/etherscan/util/BasicUtils.java (80%)
 delete mode 100644 src/test/java/io/api/ApiRunner.java
 delete mode 100644 src/test/java/io/api/etherscan/EtherScanApiTest.java
 delete mode 100644 src/test/java/io/api/manager/QueueManagerTest.java
 create mode 100644 src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
 create mode 100644 src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountBalanceListTest.java (88%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountBalanceTest.java (67%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountMinedBlocksTest.java (65%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountTokenBalanceTest.java (63%)
 rename src/test/java/io/{api/etherscan/account/AccountTxTokenTest.java => goodforgod/api/etherscan/account/AccountTxERC20Test.java} (72%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountTxInternalByHashTest.java (81%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountTxInternalTest.java (86%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountTxRc721TokenTest.java (65%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/account/AccountTxsTest.java (87%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/block/BlockApiTest.java (82%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/contract/ContractApiTest.java (78%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/logs/LogQueryBuilderTest.java (59%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/logs/LogsApiTest.java (67%)
 create mode 100644 src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyBlockApiTest.java (76%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyBlockLastNoApiTest.java (75%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyBlockUncleApiTest.java (83%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyCallApiTest.java (54%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyCodeApiTest.java (66%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyGasApiTest.java (79%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyStorageApiTest.java (76%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyTxApiTest.java (88%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyTxCountApiTest.java (81%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyTxReceiptApiTest.java (85%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/proxy/ProxyTxSendRawApiTest.java (62%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/statistic/StatisticPriceApiTest.java (81%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/statistic/StatisticSupplyApiTest.java (82%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/statistic/StatisticTokenSupplyApiTest.java (67%)
 rename src/test/java/io/{api => goodforgod/api/etherscan}/support/AddressUtil.java (98%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/transaction/TransactionExecApiTest.java (66%)
 rename src/test/java/io/{ => goodforgod}/api/etherscan/transaction/TransactionReceiptApiTest.java (61%)
 rename src/test/java/io/{api => goodforgod/api/etherscan}/util/BasicUtilsTests.java (75%)

diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 613a39e..e4c7620 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -14,7 +14,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        java: [ '11' ]
+        java: [ '11', '17' ]
     name: Java ${{ matrix.java }} setup
 
     steps:
diff --git a/README.md b/README.md
index 258b4d8..cd981ca 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
 # Java EtherScan API 
 
+[![Minimum required Java version](https://img.shields.io/badge/Java-1.8%2B-blue?logo=openjdk)](https://openjdk.org/projects/jdk8/)
 [![GitHub Action](https://github.com/goodforgod/java-etherscan-api/workflows/Java%20CI/badge.svg)](https://github.com/GoodforGod/java-etherscan-api/actions?query=workflow%3A%22Java+CI%22)
 [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=coverage)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
 [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
@@ -14,7 +15,7 @@ Library supports all available EtherScan *API* calls for all available *Ethereum
 
 **Gradle**
 ```groovy
-implementation "com.github.goodforgod:java-etherscan-api:1.3.1"
+implementation "com.github.goodforgod:java-etherscan-api:2.0.0-SNAPSHOT"
 ```
 
 **Maven**
@@ -22,7 +23,7 @@ implementation "com.github.goodforgod:java-etherscan-api:1.3.1"
 <dependency>
     <groupId>com.github.goodforgod</groupId>
     <artifactId>java-etherscan-api</artifactId>
-    <version>1.3.1</version>
+    <version>2.0.0-SNAPSHOT</version>
 </dependency>
 ```
 
diff --git a/build.gradle b/build.gradle
index 410d374..3d766c2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ plugins {
     id "maven-publish"
 
     id "org.sonarqube" version "3.3"
-    id "com.diffplug.spotless" version "6.1.0"
+    id "com.diffplug.spotless" version "6.12.0"
 }
 
 repositories {
@@ -19,13 +19,12 @@ sourceCompatibility = JavaVersion.VERSION_1_8
 targetCompatibility = JavaVersion.VERSION_1_8
 
 dependencies {
-    implementation "org.jetbrains:annotations:23.0.0"
-    implementation "com.google.code.gson:gson:2.9.0"
-    implementation "io.goodforgod:gson-configuration:1.4.1"
+    compileOnly "org.jetbrains:annotations:23.0.0"
+    implementation "io.goodforgod:gson-configuration:2.0.0"
 
-    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.2"
-    testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.2"
-    testImplementation "org.junit.jupiter:junit-jupiter-params:5.8.2"
+    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.3"
+    testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.3"
+    testImplementation "org.junit.jupiter:junit-jupiter-params:5.9.3"
 }
 
 test {
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 41dfb87..070cb70 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/src/main/java/io/api/etherscan/core/IBlockApi.java b/src/main/java/io/api/etherscan/core/IBlockApi.java
deleted file mode 100644
index df4ae96..0000000
--- a/src/main/java/io/api/etherscan/core/IBlockApi.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.api.etherscan.core;
-
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.UncleBlock;
-import java.util.Optional;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * EtherScan - API Descriptions https://etherscan.io/apis#blocks
- *
- * @author GoodforGod
- * @since 30.10.2018
- */
-public interface IBlockApi {
-
-    /**
-     * Return uncle blocks
-     * 
-     * @param blockNumber block number form 0 to last
-     * @return optional uncle blocks
-     * @throws ApiException parent exception class
-     */
-    @NotNull
-    Optional<UncleBlock> uncles(long blockNumber) throws ApiException;
-}
diff --git a/src/main/java/io/api/etherscan/core/IContractApi.java b/src/main/java/io/api/etherscan/core/IContractApi.java
deleted file mode 100644
index 3e9388d..0000000
--- a/src/main/java/io/api/etherscan/core/IContractApi.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package io.api.etherscan.core;
-
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.Abi;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * EtherScan - API Descriptions https://etherscan.io/apis#contracts
- *
- * @author GoodforGod
- * @since 28.10.2018
- */
-public interface IContractApi {
-
-    /**
-     * Get Verified Contract Sources
-     * 
-     * @param address to verify
-     * @return ABI verified
-     * @throws ApiException parent exception class
-     */
-    @NotNull
-    Abi contractAbi(String address) throws ApiException;
-}
diff --git a/src/main/java/io/api/etherscan/core/ILogsApi.java b/src/main/java/io/api/etherscan/core/ILogsApi.java
deleted file mode 100644
index 7ecd986..0000000
--- a/src/main/java/io/api/etherscan/core/ILogsApi.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.api.etherscan.core;
-
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.Log;
-import io.api.etherscan.model.query.impl.LogQuery;
-import java.util.List;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * EtherScan - API Descriptions https://etherscan.io/apis#logs
- *
- * @author GoodforGod
- * @since 30.10.2018
- */
-public interface ILogsApi {
-
-    /**
-     * alternative to the native eth_getLogs Read at EtherScan API description for full info!
-     * 
-     * @param query build log query
-     * @return logs according to query
-     * @throws ApiException parent exception class
-     * @see io.api.etherscan.model.query.impl.LogQueryBuilder
-     */
-    @NotNull
-    List<Log> logs(LogQuery query) throws ApiException;
-}
diff --git a/src/main/java/io/api/etherscan/core/IStatisticApi.java b/src/main/java/io/api/etherscan/core/IStatisticApi.java
deleted file mode 100644
index ffd633d..0000000
--- a/src/main/java/io/api/etherscan/core/IStatisticApi.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package io.api.etherscan.core;
-
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.Price;
-import io.api.etherscan.model.Supply;
-import java.math.BigInteger;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * EtherScan - API Descriptions https://etherscan.io/apis#stats
- *
- * @author GoodforGod
- * @since 30.10.2018
- */
-public interface IStatisticApi {
-
-    /**
-     * ERC20 token total Supply
-     * 
-     * @param contract contract address
-     * @return token supply for specified contract
-     * @throws ApiException parent exception class
-     */
-    @NotNull
-    BigInteger supply(String contract) throws ApiException;
-
-    /**
-     * Eth total supply
-     * 
-     * @return total ETH supply for moment
-     * @throws ApiException parent exception class
-     */
-    @NotNull
-    Supply supply() throws ApiException;
-
-    /**
-     * Eth last USD and BTC price
-     * 
-     * @return last usd/btc price for ETH
-     * @throws ApiException parent exception class
-     */
-    @NotNull
-    Price lastPrice() throws ApiException;
-}
diff --git a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java b/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
deleted file mode 100644
index ada41bb..0000000
--- a/src/main/java/io/api/etherscan/core/impl/BasicProvider.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package io.api.etherscan.core.impl;
-
-import com.google.gson.*;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.error.ParseException;
-import io.api.etherscan.error.RateLimitException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.utility.StringResponseTO;
-import io.api.etherscan.util.BasicUtils;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.Map;
-
-/**
- * Base provider for API Implementations
- *
- * @author GoodforGod
- * @see EtherScanApi
- * @since 28.10.2018
- */
-abstract class BasicProvider {
-
-    static final int MAX_END_BLOCK = Integer.MAX_VALUE;
-    static final int MIN_START_BLOCK = 0;
-
-    static final String ACT_PREFIX = "&action=";
-
-    private final String module;
-    private final String baseUrl;
-    private final IHttpExecutor executor;
-    private final IQueueManager queue;
-    private final Gson gson;
-
-    BasicProvider(final IQueueManager queue,
-                  final String module,
-                  final String baseUrl,
-                  final IHttpExecutor executor) {
-        this.queue = queue;
-        this.module = "&module=" + module;
-        this.baseUrl = baseUrl;
-        this.executor = executor;
-        this.gson = new GsonBuilder()
-                .registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (src, t, c) -> new JsonPrimitive(""))
-                .registerTypeAdapter(LocalDate.class, (JsonSerializer<LocalDate>) (src, t, context) -> new JsonPrimitive(""))
-                .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, t, c) -> null)
-                .registerTypeAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (json, t, c) -> null)
-                .create();
-    }
-
-    <T> T convert(final String json, final Class<T> tClass) {
-        try {
-            final T t = gson.fromJson(json, tClass);
-            if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith("Max rate limit reached")) {
-                throw new RateLimitException(((StringResponseTO) t).getResult());
-            }
-
-            return t;
-        } catch (Exception e) {
-            try {
-                final Map<String, Object> map = gson.fromJson(json, Map.class);
-                final Object result = map.get("result");
-                if (result instanceof String && ((String) result).startsWith("Max rate limit reached"))
-                    throw new RateLimitException(((String) result));
-
-                throw new ParseException(e.getMessage() + ", for response: " + json, e.getCause(), json);
-            } catch (ApiException ex) {
-                throw ex;
-            } catch (Exception ex) {
-                throw new ParseException(e.getMessage() + ", for response: " + json, e.getCause(), json);
-            }
-        }
-    }
-
-    String getRequest(final String urlParameters) {
-        queue.takeTurn();
-        final String url = baseUrl + module + urlParameters;
-        final String result = executor.get(url);
-        if (BasicUtils.isEmpty(result))
-            throw new EtherScanException("Server returned null value for GET request at URL - " + url);
-
-        return result;
-    }
-
-    String postRequest(final String urlParameters, final String dataToPost) {
-        queue.takeTurn();
-        final String url = baseUrl + module + urlParameters;
-        return executor.post(url, dataToPost);
-    }
-
-    <T> T getRequest(final String urlParameters, final Class<T> tClass) {
-        return convert(getRequest(urlParameters), tClass);
-    }
-
-    <T> T postRequest(final String urlParameters, final String dataToPost, final Class<T> tClass) {
-        return convert(postRequest(urlParameters, dataToPost), tClass);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java b/src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java
deleted file mode 100644
index 2e7cbea..0000000
--- a/src/main/java/io/api/etherscan/core/impl/ContractApiProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package io.api.etherscan.core.impl;
-
-import io.api.etherscan.core.IContractApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.Abi;
-import io.api.etherscan.model.utility.StringResponseTO;
-import io.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Contract API Implementation
- *
- * @see IContractApi
- * @author GoodforGod
- * @since 28.10.2018
- */
-public class ContractApiProvider extends BasicProvider implements IContractApi {
-
-    private static final String ACT_ABI_PARAM = ACT_PREFIX + "getabi";
-
-    private static final String ADDRESS_PARAM = "&address=";
-
-    ContractApiProvider(final IQueueManager queueManager,
-                        final String baseUrl,
-                        final IHttpExecutor executor) {
-        super(queueManager, "contract", baseUrl, executor);
-    }
-
-    @NotNull
-    @Override
-    public Abi contractAbi(final String address) throws ApiException {
-        BasicUtils.validateAddress(address);
-
-        final String urlParam = ACT_ABI_PARAM + ADDRESS_PARAM + address;
-        final StringResponseTO response = getRequest(urlParam, StringResponseTO.class);
-        if (response.getStatus() != 1 && "NOTOK".equals(response.getMessage()))
-            throw new EtherScanException(response);
-
-        return (response.getResult().startsWith("Contract sou"))
-                ? Abi.nonVerified()
-                : Abi.verified(response.getResult());
-    }
-}
diff --git a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
deleted file mode 100644
index aac428b..0000000
--- a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package io.api.etherscan.core.impl;
-
-import io.api.etherscan.core.*;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.ApiKeyException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.executor.impl.HttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.manager.impl.FakeQueueManager;
-import io.api.etherscan.manager.impl.QueueManager;
-import io.api.etherscan.model.EthNetwork;
-import io.api.etherscan.util.BasicUtils;
-import java.util.function.Supplier;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * EtherScan full API Description https://etherscan.io/apis
- *
- * @author GoodforGod
- * @since 28.10.2018
- */
-public class EtherScanApi implements AutoCloseable {
-
-    private static final Supplier<IHttpExecutor> DEFAULT_SUPPLIER = HttpExecutor::new;
-
-    public static final String DEFAULT_KEY = "YourApiKeyToken";
-
-    private final IQueueManager queueManager;
-    private final IAccountApi account;
-    private final IBlockApi block;
-    private final IContractApi contract;
-    private final ILogsApi logs;
-    private final IProxyApi proxy;
-    private final IStatisticApi stats;
-    private final ITransactionApi txs;
-
-    public EtherScanApi() {
-        this(DEFAULT_KEY, EthNetwork.MAINNET);
-    }
-
-    public EtherScanApi(final EthNetwork network) {
-        this(DEFAULT_KEY, network);
-    }
-
-    public EtherScanApi(final String apiKey) {
-        this(apiKey, EthNetwork.MAINNET);
-    }
-
-    public EtherScanApi(final EthNetwork network,
-                        final Supplier<IHttpExecutor> executorSupplier) {
-        this(DEFAULT_KEY, network, executorSupplier);
-    }
-
-    public EtherScanApi(final String apiKey,
-                        final EthNetwork network,
-                        final IQueueManager queue) {
-        this(apiKey, network, DEFAULT_SUPPLIER, queue);
-    }
-
-    public EtherScanApi(final String apiKey,
-                        final EthNetwork network) {
-        this(apiKey, network, DEFAULT_SUPPLIER);
-    }
-
-    public EtherScanApi(final String apiKey,
-                        final EthNetwork network,
-                        final Supplier<IHttpExecutor> executorSupplier) {
-        this(apiKey, network, executorSupplier,
-                DEFAULT_KEY.equals(apiKey)
-                        ? QueueManager.DEFAULT_KEY_QUEUE
-                        : new FakeQueueManager());
-    }
-
-    public EtherScanApi(final String apiKey,
-                        final EthNetwork network,
-                        final Supplier<IHttpExecutor> executorSupplier,
-                        final IQueueManager queue) {
-        if (BasicUtils.isBlank(apiKey))
-            throw new ApiKeyException("API key can not be null or empty");
-
-        if (network == null)
-            throw new ApiException("Ethereum Network is set to NULL value");
-
-        // EtherScan 1request\5sec limit support by queue manager
-        final IHttpExecutor executor = executorSupplier.get();
-
-        final String ending = EthNetwork.TOBALABA.equals(network)
-                ? "com"
-                : "io";
-        final String baseUrl = "https://" + network.getDomain() + ".etherscan." + ending + "/api" + "?apikey=" + apiKey;
-
-        this.queueManager = queue;
-        this.account = new AccountApiProvider(queue, baseUrl, executor);
-        this.block = new BlockApiProvider(queue, baseUrl, executor);
-        this.contract = new ContractApiProvider(queue, baseUrl, executor);
-        this.logs = new LogsApiProvider(queue, baseUrl, executor);
-        this.proxy = new ProxyApiProvider(queue, baseUrl, executor);
-        this.stats = new StatisticApiProvider(queue, baseUrl, executor);
-        this.txs = new TransactionApiProvider(queue, baseUrl, executor);
-    }
-
-    @NotNull
-    public IAccountApi account() {
-        return account;
-    }
-
-    @NotNull
-    public IContractApi contract() {
-        return contract;
-    }
-
-    @NotNull
-    public ITransactionApi txs() {
-        return txs;
-    }
-
-    @NotNull
-    public IBlockApi block() {
-        return block;
-    }
-
-    @NotNull
-    public ILogsApi logs() {
-        return logs;
-    }
-
-    @NotNull
-    public IProxyApi proxy() {
-        return proxy;
-    }
-
-    @NotNull
-    public IStatisticApi stats() {
-        return stats;
-    }
-
-    @Override
-    public void close() throws Exception {
-        queueManager.close();
-    }
-}
diff --git a/src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java b/src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java
deleted file mode 100644
index 04f9bb7..0000000
--- a/src/main/java/io/api/etherscan/core/impl/LogsApiProvider.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package io.api.etherscan.core.impl;
-
-import io.api.etherscan.core.ILogsApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.Log;
-import io.api.etherscan.model.query.impl.LogQuery;
-import io.api.etherscan.model.utility.LogResponseTO;
-import io.api.etherscan.util.BasicUtils;
-import java.util.Collections;
-import java.util.List;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Logs API Implementation
- *
- * @see ILogsApi
- * @author GoodforGod
- * @since 28.10.2018
- */
-public class LogsApiProvider extends BasicProvider implements ILogsApi {
-
-    private static final String ACT_LOGS_PARAM = ACT_PREFIX + "getLogs";
-
-    LogsApiProvider(final IQueueManager queue,
-                    final String baseUrl,
-                    final IHttpExecutor executor) {
-        super(queue, "logs", baseUrl, executor);
-    }
-
-    @NotNull
-    @Override
-    public List<Log> logs(final LogQuery query) throws ApiException {
-        final String urlParams = ACT_LOGS_PARAM + query.getParams();
-        final LogResponseTO response = getRequest(urlParams, LogResponseTO.class);
-        BasicUtils.validateTxResponse(response);
-
-        return (BasicUtils.isEmpty(response.getResult()))
-                ? Collections.emptyList()
-                : response.getResult();
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/ApiException.java b/src/main/java/io/api/etherscan/error/ApiException.java
deleted file mode 100644
index 33e4228..0000000
--- a/src/main/java/io/api/etherscan/error/ApiException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 30.10.2018
- */
-public class ApiException extends RuntimeException {
-
-    public ApiException(String message) {
-        super(message);
-    }
-
-    public ApiException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/ApiKeyException.java b/src/main/java/io/api/etherscan/error/ApiKeyException.java
deleted file mode 100644
index 4e22934..0000000
--- a/src/main/java/io/api/etherscan/error/ApiKeyException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 05.11.2018
- */
-public class ApiKeyException extends ApiException {
-
-    public ApiKeyException(String message) {
-        super(message);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/ApiTimeoutException.java b/src/main/java/io/api/etherscan/error/ApiTimeoutException.java
deleted file mode 100644
index 39b6e93..0000000
--- a/src/main/java/io/api/etherscan/error/ApiTimeoutException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 12.11.2018
- */
-public class ApiTimeoutException extends ApiException {
-
-    public ApiTimeoutException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/ConnectionException.java b/src/main/java/io/api/etherscan/error/ConnectionException.java
deleted file mode 100644
index 96a881c..0000000
--- a/src/main/java/io/api/etherscan/error/ConnectionException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class ConnectionException extends ApiException {
-
-    public ConnectionException(String message) {
-        super(message);
-    }
-
-    public ConnectionException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/EtherScanException.java b/src/main/java/io/api/etherscan/error/EtherScanException.java
deleted file mode 100644
index cb7dd7f..0000000
--- a/src/main/java/io/api/etherscan/error/EtherScanException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package io.api.etherscan.error;
-
-import io.api.etherscan.model.utility.BaseResponseTO;
-import io.api.etherscan.model.utility.StringResponseTO;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class EtherScanException extends ApiException {
-
-    public EtherScanException(BaseResponseTO response) {
-        this(response.getMessage() + ", with status: " + response.getStatus());
-    }
-
-    public EtherScanException(StringResponseTO response) {
-        this(response.getResult() + ", with status: " + response.getStatus() + ", with message: " + response.getMessage());
-    }
-
-    public EtherScanException(String message) {
-        super(message);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/EventModelException.java b/src/main/java/io/api/etherscan/error/EventModelException.java
deleted file mode 100644
index feb60be..0000000
--- a/src/main/java/io/api/etherscan/error/EventModelException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-public class EventModelException extends ApiException {
-
-    public EventModelException(String message) {
-        super(message);
-    }
-
-    public EventModelException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/InvalidAddressException.java b/src/main/java/io/api/etherscan/error/InvalidAddressException.java
deleted file mode 100644
index 9a0c143..0000000
--- a/src/main/java/io/api/etherscan/error/InvalidAddressException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class InvalidAddressException extends ApiException {
-
-    public InvalidAddressException(String message) {
-        super(message);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/InvalidDataHexException.java b/src/main/java/io/api/etherscan/error/InvalidDataHexException.java
deleted file mode 100644
index dd12cb9..0000000
--- a/src/main/java/io/api/etherscan/error/InvalidDataHexException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 02.11.2018
- */
-public class InvalidDataHexException extends ApiException {
-
-    public InvalidDataHexException(String message) {
-        super(message);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/InvalidTxHashException.java b/src/main/java/io/api/etherscan/error/InvalidTxHashException.java
deleted file mode 100644
index aba32c1..0000000
--- a/src/main/java/io/api/etherscan/error/InvalidTxHashException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 02.11.2018
- */
-public class InvalidTxHashException extends ApiException {
-
-    public InvalidTxHashException(String message) {
-        super(message);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/LogQueryException.java b/src/main/java/io/api/etherscan/error/LogQueryException.java
deleted file mode 100644
index 504219f..0000000
--- a/src/main/java/io/api/etherscan/error/LogQueryException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 31.10.2018
- */
-public class LogQueryException extends ApiException {
-
-    public LogQueryException(String message) {
-        super(message);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/error/RateLimitException.java b/src/main/java/io/api/etherscan/error/RateLimitException.java
deleted file mode 100644
index c29f54d..0000000
--- a/src/main/java/io/api/etherscan/error/RateLimitException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.api.etherscan.error;
-
-/**
- * @author iSnow
- * @since 2020-10-06
- */
-public class RateLimitException extends ApiException {
-
-    public RateLimitException(String message) {
-        super(message);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/manager/IQueueManager.java b/src/main/java/io/api/etherscan/manager/IQueueManager.java
deleted file mode 100644
index 98a3172..0000000
--- a/src/main/java/io/api/etherscan/manager/IQueueManager.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.api.etherscan.manager;
-
-/**
- * Queue manager to support API limits (EtherScan 5request\sec limit) Managers grants turn if the
- * limit is not exhausted And resets queue each set period
- *
- * @author GoodforGod
- * @since 30.10.2018
- */
-public interface IQueueManager extends AutoCloseable {
-
-    /**
-     * Waits in queue for chance to take turn
-     */
-    void takeTurn();
-}
diff --git a/src/main/java/io/api/etherscan/manager/impl/QueueManager.java b/src/main/java/io/api/etherscan/manager/impl/QueueManager.java
deleted file mode 100644
index d3a44de..0000000
--- a/src/main/java/io/api/etherscan/manager/impl/QueueManager.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package io.api.etherscan.manager.impl;
-
-import io.api.etherscan.manager.IQueueManager;
-import java.util.concurrent.*;
-
-/**
- * Queue Semaphore implementation with size and reset time as params
- * 
- * @see IQueueManager
- * @author GoodforGod
- * @since 30.10.2018
- */
-public class QueueManager implements IQueueManager, AutoCloseable {
-
-    public static final QueueManager DEFAULT_KEY_QUEUE = new QueueManager(1, 5200L, 5200L, 0);
-    public static final QueueManager PERSONAL_KEY_QUEUE = new QueueManager(5, 1100L, 1100L, 5);
-
-    private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
-    private final Semaphore semaphore;
-    private final long queueResetTimeInMillis;
-
-    public QueueManager(int size, int resetInSec) {
-        this(size, resetInSec, resetInSec);
-    }
-
-    public QueueManager(int size, int queueResetTimeInSec, int delayInSec) {
-        this(size, queueResetTimeInSec, delayInSec, size);
-    }
-
-    public QueueManager(int size, int queueResetTimeInSec, int delayInSec, int initialSize) {
-        this(size,
-                (long) queueResetTimeInSec * 1000,
-                (long) delayInSec * 1000,
-                initialSize);
-    }
-
-    public QueueManager(int size, long queueResetTimeInMillis, long delayInMillis, int initialSize) {
-        this.queueResetTimeInMillis = queueResetTimeInMillis;
-        this.semaphore = new Semaphore(initialSize);
-        this.executorService.scheduleAtFixedRate(releaseLocks(size), delayInMillis, queueResetTimeInMillis,
-                TimeUnit.MILLISECONDS);
-    }
-
-    @SuppressWarnings("java:S899")
-    @Override
-    public void takeTurn() {
-        try {
-            semaphore.tryAcquire(queueResetTimeInMillis, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    private Runnable releaseLocks(int toRelease) {
-        return () -> semaphore.release(toRelease);
-    }
-
-    @Override
-    public void close() {
-        executorService.shutdown();
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/EthNetwork.java b/src/main/java/io/api/etherscan/model/EthNetwork.java
deleted file mode 100644
index 6144cf1..0000000
--- a/src/main/java/io/api/etherscan/model/EthNetwork.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.api.etherscan.model;
-
-/**
- * @author GoodforGod
- * @since 28.10.2018
- */
-public enum EthNetwork {
-
-    MAINNET("api"),
-    ROPSTEN("api-ropsten"),
-    KOVAN("api-kovan"),
-    TOBALABA("api-tobalaba"),
-    GORLI("api-goerli"),
-    RINKEBY("api-rinkeby");
-
-    private final String domain;
-
-    EthNetwork(String domain) {
-        this.domain = domain;
-    }
-
-    public String getDomain() {
-        return domain;
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/Uncle.java b/src/main/java/io/api/etherscan/model/Uncle.java
deleted file mode 100644
index 7dea648..0000000
--- a/src/main/java/io/api/etherscan/model/Uncle.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package io.api.etherscan.model;
-
-import java.math.BigInteger;
-
-/**
- * @author GoodforGod
- * @since 30.10.2018
- */
-public class Uncle {
-
-    private String miner;
-    private BigInteger blockreward;
-    private int unclePosition;
-
-    // <editor-fold desc="Getters">
-    public String getMiner() {
-        return miner;
-    }
-
-    public BigInteger getBlockreward() {
-        return blockreward;
-    }
-
-    public int getUnclePosition() {
-        return unclePosition;
-    }
-    // </editor-fold>
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (o == null || getClass() != o.getClass())
-            return false;
-
-        Uncle uncle = (Uncle) o;
-
-        if (unclePosition != uncle.unclePosition)
-            return false;
-        if (miner != null
-                ? !miner.equals(uncle.miner)
-                : uncle.miner != null)
-            return false;
-        return blockreward != null
-                ? blockreward.equals(uncle.blockreward)
-                : uncle.blockreward == null;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = miner != null
-                ? miner.hashCode()
-                : 0;
-        result = 31 * result + (blockreward != null
-                ? blockreward.hashCode()
-                : 0);
-        result = 31 * result + unclePosition;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "Uncle{" +
-                "miner='" + miner + '\'' +
-                ", blockreward=" + blockreward +
-                ", unclePosition=" + unclePosition +
-                '}';
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/UncleBlock.java b/src/main/java/io/api/etherscan/model/UncleBlock.java
deleted file mode 100644
index ff30451..0000000
--- a/src/main/java/io/api/etherscan/model/UncleBlock.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package io.api.etherscan.model;
-
-import io.api.etherscan.util.BasicUtils;
-import java.util.List;
-
-/**
- * @author GoodforGod
- * @since 30.10.2018
- */
-public class UncleBlock extends Block {
-
-    private String blockMiner;
-    private List<Uncle> uncles;
-    private String uncleInclusionReward;
-
-    // <editor-fold desc="Getters">
-    public boolean isEmpty() {
-        return getBlockNumber() == 0 && getBlockReward() == null
-                && getTimeStamp() == null
-                && BasicUtils.isEmpty(blockMiner);
-    }
-
-    public String getBlockMiner() {
-        return blockMiner;
-    }
-
-    public List<Uncle> getUncles() {
-        return uncles;
-    }
-
-    public String getUncleInclusionReward() {
-        return uncleInclusionReward;
-    }
-    // </editor-fold>
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (o == null || getClass() != o.getClass())
-            return false;
-        if (!super.equals(o))
-            return false;
-
-        UncleBlock that = (UncleBlock) o;
-
-        return getBlockNumber() != 0 && getBlockNumber() == that.getBlockNumber();
-    }
-
-    @Override
-    public int hashCode() {
-        int result = super.hashCode();
-        result = (int) (31 * result + getBlockNumber());
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "UncleBlock{" +
-                "blockMiner='" + blockMiner + '\'' +
-                ", uncles=" + uncles +
-                ", uncleInclusionReward='" + uncleInclusionReward + '\'' +
-                '}';
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/query/IQueryBuilder.java b/src/main/java/io/api/etherscan/model/query/IQueryBuilder.java
deleted file mode 100644
index 6a76c62..0000000
--- a/src/main/java/io/api/etherscan/model/query/IQueryBuilder.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.api.etherscan.model.query;
-
-import io.api.etherscan.error.LogQueryException;
-import io.api.etherscan.model.query.impl.LogQuery;
-
-/**
- * Builder, part of The Event Log API
- *
- * @author GoodforGod
- * @since 31.10.2018
- */
-public interface IQueryBuilder {
-
-    LogQuery build() throws LogQueryException;
-}
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogQuery.java b/src/main/java/io/api/etherscan/model/query/impl/LogQuery.java
deleted file mode 100644
index 31d8c13..0000000
--- a/src/main/java/io/api/etherscan/model/query/impl/LogQuery.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package io.api.etherscan.model.query.impl;
-
-import io.api.etherscan.core.ILogsApi;
-
-/**
- * Final builded container for The Event Log API
- * EtherScan - API Descriptions https://etherscan.io/apis#logs
- *
- * @see LogQueryBuilder
- * @see ILogsApi
- * @author GoodforGod
- * @since 31.10.2018
- */
-public class LogQuery {
-
-    /**
-     * Final request parameter for api call
-     */
-    private final String params;
-
-    LogQuery(String params) {
-        this.params = params;
-    }
-
-    public String getParams() {
-        return params;
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java b/src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java
deleted file mode 100644
index 44ca825..0000000
--- a/src/main/java/io/api/etherscan/model/query/impl/LogQueryBuilder.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package io.api.etherscan.model.query.impl;
-
-import io.api.etherscan.core.ILogsApi;
-import io.api.etherscan.error.LogQueryException;
-import io.api.etherscan.model.query.IQueryBuilder;
-import io.api.etherscan.util.BasicUtils;
-
-/**
- * Builder for The Event Log API
- *
- * @see ILogsApi
- * @author GoodforGod
- * @since 31.10.2018
- */
-public class LogQueryBuilder implements IQueryBuilder {
-
-    private static final long MIN_BLOCK = 0;
-    private static final long MAX_BLOCK = 99999999999L;
-
-    private final String address;
-    private final long startBlock, endBlock;
-
-    private LogQueryBuilder(String address, long startBlock, long endBlock) {
-        this.address = address;
-        this.startBlock = startBlock;
-        this.endBlock = endBlock;
-    }
-
-    public static LogQueryBuilder with(String address) {
-        return with(address, MIN_BLOCK);
-    }
-
-    public static LogQueryBuilder with(String address, long startBlock) {
-        return with(address, startBlock, MAX_BLOCK);
-    }
-
-    public static LogQueryBuilder with(String address, long startBlock, long endBlock) {
-        BasicUtils.validateAddress(address);
-        return new LogQueryBuilder(address, startBlock, endBlock);
-    }
-
-    public LogTopicSingle topic(String topic0) {
-        if (BasicUtils.isNotHex(topic0))
-            throw new LogQueryException("topic0 can not be empty or non hex.");
-        return new LogTopicSingle(address, startBlock, endBlock, topic0);
-    }
-
-    public LogTopicTuple topic(String topic0, String topic1) {
-        if (BasicUtils.isNotHex(topic0))
-            throw new LogQueryException("topic0 can not be empty or non hex.");
-        if (BasicUtils.isNotHex(topic1))
-            throw new LogQueryException("topic1 can not be empty or non hex.");
-        return new LogTopicTuple(address, startBlock, endBlock, topic0, topic1);
-    }
-
-    public LogTopicTriple topic(String topic0, String topic1, String topic2) {
-        if (BasicUtils.isNotHex(topic0))
-            throw new LogQueryException("topic0 can not be empty or non hex.");
-        if (BasicUtils.isNotHex(topic1))
-            throw new LogQueryException("topic1 can not be empty or non hex.");
-        if (BasicUtils.isNotHex(topic2))
-            throw new LogQueryException("topic2 can not be empty or non hex.");
-        return new LogTopicTriple(address, startBlock, endBlock, topic0, topic1, topic2);
-    }
-
-    public LogTopicQuadro topic(String topic0, String topic1, String topic2, String topic3) {
-        if (BasicUtils.isNotHex(topic0))
-            throw new LogQueryException("topic0 can not be empty or non hex.");
-        if (BasicUtils.isNotHex(topic1))
-            throw new LogQueryException("topic1 can not be empty or non hex.");
-        if (BasicUtils.isNotHex(topic2))
-            throw new LogQueryException("topic2 can not be empty or non hex.");
-        if (BasicUtils.isNotHex(topic3))
-            throw new LogQueryException("topic3 can not be empty or non hex.");
-
-        return new LogTopicQuadro(address, startBlock, endBlock, topic0, topic1, topic2, topic3);
-    }
-
-    @Override
-    public LogQuery build() throws LogQueryException {
-        return new LogQuery("&address=" + this.address + "&fromBlock=" + this.startBlock + "&toBlock=" + this.endBlock);
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java b/src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java
deleted file mode 100644
index 1cbd4e3..0000000
--- a/src/main/java/io/api/etherscan/model/utility/TxTokenResponseTO.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.api.etherscan.model.utility;
-
-import io.api.etherscan.model.TxToken;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class TxTokenResponseTO extends BaseListResponseTO<TxToken> {
-
-}
diff --git a/src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java b/src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java
deleted file mode 100644
index f8e4c5e..0000000
--- a/src/main/java/io/api/etherscan/model/utility/UncleBlockResponseTO.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.api.etherscan.model.utility;
-
-import io.api.etherscan.model.UncleBlock;
-
-/**
- * @author GoodforGod
- * @since 30.10.2018
- */
-public class UncleBlockResponseTO extends BaseResponseTO {
-
-    private UncleBlock result;
-
-    public UncleBlock getResult() {
-        return result;
-    }
-}
diff --git a/src/main/java/io/api/etherscan/core/IAccountApi.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
similarity index 55%
rename from src/main/java/io/api/etherscan/core/IAccountApi.java
rename to src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
index ee869a2..7a0df39 100644
--- a/src/main/java/io/api/etherscan/core/IAccountApi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
@@ -1,27 +1,27 @@
-package io.api.etherscan.core;
+package io.goodforgod.api.etherscan;
 
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.*;
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.*;
 import java.util.List;
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions https://etherscan.io/apis#accounts
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#accounts">...</a>
  *
  * @author GoodforGod
  * @since 28.10.2018
  */
-public interface IAccountApi {
+public interface AccountAPI {
 
     /**
      * Address ETH balance
      * 
      * @param address get balance for
      * @return balance
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Balance balance(String address) throws ApiException;
+    Balance balance(String address) throws EtherScanException;
 
     /**
      * ERC20 token balance for address
@@ -29,10 +29,10 @@ public interface IAccountApi {
      * @param address  get balance for
      * @param contract token contract
      * @return token balance for address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    TokenBalance balance(String address, String contract) throws ApiException;
+    TokenBalance balance(String address, String contract) throws EtherScanException;
 
     /**
      * Maximum 20 address for single batch request If address MORE THAN 20, then there will be more than
@@ -40,10 +40,10 @@ public interface IAccountApi {
      * 
      * @param addresses addresses to get balances for
      * @return list of balances
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<Balance> balances(List<String> addresses) throws ApiException;
+    List<Balance> balances(List<String> addresses) throws EtherScanException;
 
     /**
      * All txs for given address
@@ -52,16 +52,16 @@ public interface IAccountApi {
      * @param startBlock tx from this blockNumber
      * @param endBlock   tx to this blockNumber
      * @return txs for address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<Tx> txs(String address, long startBlock, long endBlock) throws ApiException;
+    List<Tx> txs(String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<Tx> txs(String address, long startBlock) throws ApiException;
+    List<Tx> txs(String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<Tx> txs(String address) throws ApiException;
+    List<Tx> txs(String address) throws EtherScanException;
 
     /**
      * All internal txs for given address
@@ -70,26 +70,26 @@ public interface IAccountApi {
      * @param startBlock tx from this blockNumber
      * @param endBlock   tx to this blockNumber
      * @return txs for address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxInternal> txsInternal(String address, long startBlock, long endBlock) throws ApiException;
+    List<TxInternal> txsInternal(String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxInternal> txsInternal(String address, long startBlock) throws ApiException;
+    List<TxInternal> txsInternal(String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxInternal> txsInternal(String address) throws ApiException;
+    List<TxInternal> txsInternal(String address) throws EtherScanException;
 
     /**
      * All internal tx for given transaction hash
      * 
      * @param txhash transaction hash
      * @return internal txs list
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxInternal> txsInternalByHash(String txhash) throws ApiException;
+    List<TxInternal> txsInternalByHash(String txhash) throws EtherScanException;
 
     /**
      * All ERC-20 token txs for given address
@@ -98,16 +98,16 @@ public interface IAccountApi {
      * @param startBlock tx from this blockNumber
      * @param endBlock   tx to this blockNumber
      * @return txs for address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxToken> txsToken(String address, long startBlock, long endBlock) throws ApiException;
+    List<TxERC20> txsERC20(String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxToken> txsToken(String address, long startBlock) throws ApiException;
+    List<TxERC20> txsERC20(String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxToken> txsToken(String address) throws ApiException;
+    List<TxERC20> txsERC20(String address) throws EtherScanException;
 
     /**
      * All ERC-721 (NFT) token txs for given address
@@ -116,24 +116,24 @@ public interface IAccountApi {
      * @param startBlock tx from this blockNumber
      * @param endBlock   tx to this blockNumber
      * @return txs for address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxToken> txsNftToken(String address, long startBlock, long endBlock) throws ApiException;
+    List<TxERC721> txsERC721(String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxToken> txsNftToken(String address, long startBlock) throws ApiException;
+    List<TxERC721> txsERC721(String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxToken> txsNftToken(String address) throws ApiException;
+    List<TxERC721> txsERC721(String address) throws EtherScanException;
 
     /**
      * All blocks mined by address
      * 
      * @param address address to search for
      * @return blocks mined
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<Block> minedBlocks(String address) throws ApiException;
+    List<Block> blocksMined(String address) throws EtherScanException;
 }
diff --git a/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
similarity index 59%
rename from src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
rename to src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index c807598..7cc5f52 100644
--- a/src/main/java/io/api/etherscan/core/impl/AccountApiProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -1,13 +1,12 @@
-package io.api.etherscan.core.impl;
-
-import io.api.etherscan.core.IAccountApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.*;
-import io.api.etherscan.model.utility.*;
-import io.api.etherscan.util.BasicUtils;
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.*;
+import io.goodforgod.api.etherscan.model.response.*;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -18,11 +17,11 @@
 /**
  * Account API Implementation
  *
- * @see IAccountApi
+ * @see AccountAPI
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class AccountApiProvider extends BasicProvider implements IAccountApi {
+final class AccountAPIProvider extends BasicProvider implements AccountAPI {
 
     private static final int OFFSET_MAX = 10000;
 
@@ -47,42 +46,42 @@ public class AccountApiProvider extends BasicProvider implements IAccountApi {
     private static final String OFFSET_PARAM = "&offset=";
     private static final String PAGE_PARAM = "&page=";
 
-    AccountApiProvider(final IQueueManager queueManager,
-                       final String baseUrl,
-                       final IHttpExecutor executor) {
-        super(queueManager, "account", baseUrl, executor);
+    AccountAPIProvider(RequestQueueManager requestQueueManager,
+                       String baseUrl,
+                       EthHttpClient executor) {
+        super(requestQueueManager, "account", baseUrl, executor);
     }
 
     @NotNull
     @Override
-    public Balance balance(final String address) throws ApiException {
+    public Balance balance(String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_BALANCE_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + address;
         final StringResponseTO response = getRequest(urlParams, StringResponseTO.class);
         if (response.getStatus() != 1)
-            throw new EtherScanException(response);
+            throw new EtherScanResponseException(response);
 
         return new Balance(address, new BigInteger(response.getResult()));
     }
 
     @NotNull
     @Override
-    public TokenBalance balance(final String address, final String contract) throws ApiException {
+    public TokenBalance balance(String address, String contract) throws EtherScanException {
         BasicUtils.validateAddress(address);
         BasicUtils.validateAddress(contract);
 
         final String urlParams = ACT_TOKEN_BALANCE_PARAM + ADDRESS_PARAM + address + CONTRACT_PARAM + contract;
         final StringResponseTO response = getRequest(urlParams, StringResponseTO.class);
         if (response.getStatus() != 1)
-            throw new EtherScanException(response);
+            throw new EtherScanResponseException(response);
 
         return new TokenBalance(address, new BigInteger(response.getResult()), contract);
     }
 
     @NotNull
     @Override
-    public List<Balance> balances(final List<String> addresses) throws ApiException {
+    public List<Balance> balances(List<String> addresses) throws EtherScanException {
         if (BasicUtils.isEmpty(addresses))
             return Collections.emptyList();
 
@@ -96,7 +95,7 @@ public List<Balance> balances(final List<String> addresses) throws ApiException
             final String urlParams = ACT_BALANCE_MULTI_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + toAddressParam(batch);
             final BalanceResponseTO response = getRequest(urlParams, BalanceResponseTO.class);
             if (response.getStatus() != 1)
-                throw new EtherScanException(response);
+                throw new EtherScanResponseException(response);
 
             if (!BasicUtils.isEmpty(response.getResult()))
                 balances.addAll(response.getResult().stream()
@@ -107,31 +106,32 @@ public List<Balance> balances(final List<String> addresses) throws ApiException
         return balances;
     }
 
-    private String toAddressParam(final List<String> addresses) {
-        return addresses.stream().collect(Collectors.joining(","));
+    private String toAddressParam(List<String> addresses) {
+        return String.join(",", addresses);
     }
 
     @NotNull
     @Override
-    public List<Tx> txs(final String address) throws ApiException {
+    public List<Tx> txs(String address) throws EtherScanException {
         return txs(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<Tx> txs(final String address, final long startBlock) throws ApiException {
+    public List<Tx> txs(String address, long startBlock) throws EtherScanException {
         return txs(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<Tx> txs(final String address, final long startBlock, final long endBlock) throws ApiException {
+    public List<Tx> txs(String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
-        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
-        final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
-        final String urlParams = ACT_TX_ACTION + offsetParam + ADDRESS_PARAM + address + blockParam + SORT_ASC_PARAM;
+        final String urlParams = ACT_TX_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
+                + ADDRESS_PARAM + address
+                + START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end()
+                + SORT_ASC_PARAM;
 
         return getRequestUsingOffset(urlParams, TxResponseTO.class);
     }
@@ -147,7 +147,7 @@ public List<Tx> txs(final String address, final long startBlock, final long endB
      */
     private <T, R extends BaseListResponseTO> List<T> getRequestUsingOffset(final String urlParams,
                                                                             Class<R> tClass)
-            throws ApiException {
+            throws EtherScanException {
         final List<T> result = new ArrayList<>();
         int page = 1;
         while (true) {
@@ -167,32 +167,34 @@ private <T, R extends BaseListResponseTO> List<T> getRequestUsingOffset(final St
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternal(final String address) throws ApiException {
+    public List<TxInternal> txsInternal(String address) throws EtherScanException {
         return txsInternal(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternal(final String address, final long startBlock) throws ApiException {
+    public List<TxInternal> txsInternal(String address, long startBlock) throws EtherScanException {
         return txsInternal(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternal(final String address, final long startBlock, final long endBlock) throws ApiException {
+    public List<TxInternal> txsInternal(String address, long startBlock, long endBlock)
+            throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
-        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
-        final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
-        final String urlParams = ACT_TX_INTERNAL_ACTION + offsetParam + ADDRESS_PARAM + address + blockParam + SORT_ASC_PARAM;
+        final String urlParams = ACT_TX_INTERNAL_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
+                + ADDRESS_PARAM + address
+                + START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end()
+                + SORT_ASC_PARAM;
 
         return getRequestUsingOffset(urlParams, TxInternalResponseTO.class);
     }
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternalByHash(final String txhash) throws ApiException {
+    public List<TxInternal> txsInternalByHash(String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_INTERNAL_ACTION + TXHASH_PARAM + txhash;
@@ -206,61 +208,63 @@ public List<TxInternal> txsInternalByHash(final String txhash) throws ApiExcepti
 
     @NotNull
     @Override
-    public List<TxToken> txsToken(final String address) throws ApiException {
-        return txsToken(address, MIN_START_BLOCK);
+    public List<TxERC20> txsERC20(String address) throws EtherScanException {
+        return txsERC20(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxToken> txsToken(final String address, final long startBlock) throws ApiException {
-        return txsToken(address, startBlock, MAX_END_BLOCK);
+    public List<TxERC20> txsERC20(String address, long startBlock) throws EtherScanException {
+        return txsERC20(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxToken> txsToken(final String address, final long startBlock, final long endBlock) throws ApiException {
+    public List<TxERC20> txsERC20(String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
-        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
-        final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
-        final String urlParams = ACT_TX_TOKEN_ACTION + offsetParam + ADDRESS_PARAM + address + blockParam + SORT_ASC_PARAM;
+        final String urlParams = ACT_TX_TOKEN_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
+                + ADDRESS_PARAM + address
+                + START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end()
+                + SORT_ASC_PARAM;
 
-        return getRequestUsingOffset(urlParams, TxTokenResponseTO.class);
+        return getRequestUsingOffset(urlParams, TxERC20ResponseTO.class);
     }
 
     @NotNull
     @Override
-    public List<TxToken> txsNftToken(String address) throws ApiException {
-        return txsNftToken(address, MIN_START_BLOCK);
+    public List<TxERC721> txsERC721(String address) throws EtherScanException {
+        return txsERC721(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxToken> txsNftToken(String address, long startBlock) throws ApiException {
-        return txsNftToken(address, startBlock, MAX_END_BLOCK);
+    public List<TxERC721> txsERC721(String address, long startBlock) throws EtherScanException {
+        return txsERC721(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxToken> txsNftToken(String address, long startBlock, long endBlock) throws ApiException {
+    public List<TxERC721> txsERC721(String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
-        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
-        final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
-        final String urlParams = ACT_TX_NFT_TOKEN_ACTION + offsetParam + ADDRESS_PARAM + address + blockParam + SORT_ASC_PARAM;
+        final String urlParams = ACT_TX_NFT_TOKEN_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
+                + ADDRESS_PARAM + address
+                + START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end()
+                + SORT_ASC_PARAM;
 
-        return getRequestUsingOffset(urlParams, TxTokenResponseTO.class);
+        return getRequestUsingOffset(urlParams, TxERC20ResponseTO.class);
     }
 
     @NotNull
     @Override
-    public List<Block> minedBlocks(final String address) throws ApiException {
+    public List<Block> blocksMined(String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
-        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
-        final String urlParams = ACT_MINED_ACTION + offsetParam + BLOCK_TYPE_PARAM + ADDRESS_PARAM + address;
+        final String urlParams = ACT_MINED_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX + BLOCK_TYPE_PARAM
+                + ADDRESS_PARAM + address;
 
         return getRequestUsingOffset(urlParams, BlockResponseTO.class);
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
new file mode 100644
index 0000000..4fd625a
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -0,0 +1,93 @@
+package io.goodforgod.api.etherscan;
+
+import com.google.gson.*;
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.error.EtherScanParseException;
+import io.goodforgod.api.etherscan.error.EtherScanRateLimitException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.response.StringResponseTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
+import io.goodforgod.gson.configuration.GsonConfiguration;
+import java.util.Map;
+
+/**
+ * Base provider for API Implementations
+ *
+ * @author GoodforGod
+ * @see EtherScanAPIProvider
+ * @since 28.10.2018
+ */
+abstract class BasicProvider {
+
+    static final int MAX_END_BLOCK = Integer.MAX_VALUE;
+    static final int MIN_START_BLOCK = 0;
+
+    static final String ACT_PREFIX = "&action=";
+
+    private final String module;
+    private final String baseUrl;
+    private final EthHttpClient executor;
+    private final RequestQueueManager queue;
+    private final Gson gson;
+
+    BasicProvider(RequestQueueManager queue,
+                  String module,
+                  String baseUrl,
+                  EthHttpClient executor) {
+        this.queue = queue;
+        this.module = "&module=" + module;
+        this.baseUrl = baseUrl;
+        this.executor = executor;
+        this.gson = new GsonConfiguration().builder().create();
+    }
+
+    <T> T convert(String json, Class<T> tClass) {
+        try {
+            final T t = gson.fromJson(json, tClass);
+            if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith("Max rate limit reached")) {
+                throw new EtherScanRateLimitException(((StringResponseTO) t).getResult());
+            }
+
+            return t;
+        } catch (Exception e) {
+            try {
+                final Map<String, Object> map = gson.fromJson(json, Map.class);
+                final Object result = map.get("result");
+                if (result instanceof String && ((String) result).startsWith("Max rate limit reached"))
+                    throw new EtherScanRateLimitException(((String) result));
+
+                throw new EtherScanParseException(e.getMessage() + ", for response: " + json, e.getCause(), json);
+            } catch (EtherScanException ex) {
+                throw ex;
+            } catch (Exception ex) {
+                throw new EtherScanParseException(e.getMessage() + ", for response: " + json, e.getCause(), json);
+            }
+        }
+    }
+
+    String getRequest(String urlParameters) {
+        queue.takeTurn();
+        final String url = baseUrl + module + urlParameters;
+        final String result = executor.get(url);
+        if (BasicUtils.isEmpty(result))
+            throw new EtherScanResponseException("Server returned null value for GET request at URL - " + url);
+
+        return result;
+    }
+
+    String postRequest(String urlParameters, String dataToPost) {
+        queue.takeTurn();
+        final String url = baseUrl + module + urlParameters;
+        return executor.post(url, dataToPost);
+    }
+
+    <T> T getRequest(String urlParameters, Class<T> tClass) {
+        return convert(getRequest(urlParameters), tClass);
+    }
+
+    <T> T postRequest(String urlParameters, String dataToPost, Class<T> tClass) {
+        return convert(postRequest(urlParameters, dataToPost), tClass);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/BlockAPI.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPI.java
new file mode 100644
index 0000000..55a8c3b
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPI.java
@@ -0,0 +1,25 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.BlockUncle;
+import java.util.Optional;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#blocks">...</a>
+ *
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public interface BlockAPI {
+
+    /**
+     * Return uncle blocks
+     * 
+     * @param blockNumber block number form 0 to last
+     * @return optional uncle blocks
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    Optional<BlockUncle> uncles(long blockNumber) throws EtherScanException;
+}
diff --git a/src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
similarity index 53%
rename from src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java
rename to src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
index d634c9b..e5a6d49 100644
--- a/src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
@@ -1,37 +1,36 @@
-package io.api.etherscan.core.impl;
+package io.goodforgod.api.etherscan;
 
-import io.api.etherscan.core.IBlockApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.UncleBlock;
-import io.api.etherscan.model.utility.UncleBlockResponseTO;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.BlockUncle;
+import io.goodforgod.api.etherscan.model.response.UncleBlockResponseTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.util.Optional;
 import org.jetbrains.annotations.NotNull;
 
 /**
  * Block API Implementation
  *
- * @see IBlockApi
+ * @see BlockAPI
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class BlockApiProvider extends BasicProvider implements IBlockApi {
+final class BlockAPIProvider extends BasicProvider implements BlockAPI {
 
     private static final String ACT_BLOCK_PARAM = ACT_PREFIX + "getblockreward";
 
     private static final String BLOCKNO_PARAM = "&blockno=";
 
-    BlockApiProvider(final IQueueManager queueManager,
-                     final String baseUrl,
-                     final IHttpExecutor executor) {
-        super(queueManager, "block", baseUrl, executor);
+    BlockAPIProvider(RequestQueueManager requestQueueManager,
+                     String baseUrl,
+                     EthHttpClient executor) {
+        super(requestQueueManager, "block", baseUrl, executor);
     }
 
     @NotNull
     @Override
-    public Optional<UncleBlock> uncles(long blockNumber) throws ApiException {
+    public Optional<BlockUncle> uncles(long blockNumber) throws EtherScanException {
         final String urlParam = ACT_BLOCK_PARAM + BLOCKNO_PARAM + blockNumber;
         final String response = getRequest(urlParam);
         if (BasicUtils.isEmpty(response) || response.contains("NOTOK"))
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
new file mode 100644
index 0000000..9271347
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
@@ -0,0 +1,24 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.Abi;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#contracts">...</a>
+ *
+ * @author GoodforGod
+ * @since 28.10.2018
+ */
+public interface ContractAPI {
+
+    /**
+     * Get Verified Contract Sources
+     * 
+     * @param address to verify
+     * @return ABI verified
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    Abi contractAbi(String address) throws EtherScanException;
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
new file mode 100644
index 0000000..cd96f68
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -0,0 +1,45 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.Abi;
+import io.goodforgod.api.etherscan.model.response.StringResponseTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Contract API Implementation
+ *
+ * @see ContractAPI
+ * @author GoodforGod
+ * @since 28.10.2018
+ */
+final class ContractAPIProvider extends BasicProvider implements ContractAPI {
+
+    private static final String ACT_ABI_PARAM = ACT_PREFIX + "getabi";
+
+    private static final String ADDRESS_PARAM = "&address=";
+
+    ContractAPIProvider(RequestQueueManager requestQueueManager,
+                        String baseUrl,
+                        EthHttpClient executor) {
+        super(requestQueueManager, "contract", baseUrl, executor);
+    }
+
+    @NotNull
+    @Override
+    public Abi contractAbi(String address) throws EtherScanException {
+        BasicUtils.validateAddress(address);
+
+        final String urlParam = ACT_ABI_PARAM + ADDRESS_PARAM + address;
+        final StringResponseTO response = getRequest(urlParam, StringResponseTO.class);
+        if (response.getStatus() != 1 && "NOTOK".equals(response.getMessage()))
+            throw new EtherScanResponseException(response);
+
+        return (response.getResult().startsWith("Contract sou"))
+                ? Abi.nonVerified()
+                : Abi.verified(response.getResult());
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthNetwork.java b/src/main/java/io/goodforgod/api/etherscan/EthNetwork.java
new file mode 100644
index 0000000..ce0d929
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/EthNetwork.java
@@ -0,0 +1,14 @@
+package io.goodforgod.api.etherscan;
+
+import java.net.URI;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Anton Kurako (GoodforGod)
+ * @since 11.05.2023
+ */
+public interface EthNetwork {
+
+    @NotNull
+    URI domain();
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthNetworks.java b/src/main/java/io/goodforgod/api/etherscan/EthNetworks.java
new file mode 100644
index 0000000..4dbe138
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/EthNetworks.java
@@ -0,0 +1,29 @@
+package io.goodforgod.api.etherscan;
+
+import java.net.URI;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author GoodforGod
+ * @since 28.10.2018
+ */
+public enum EthNetworks implements EthNetwork {
+
+    MAINNET("api", "io"),
+    ROPSTEN("api-ropsten", "io"),
+    KOVAN("api-kovan", "io"),
+    TOBALABA("api-tobalaba", "com"),
+    GORLI("api-goerli", "io"),
+    RINKEBY("api-rinkeby", "io");
+
+    private final URI domain;
+
+    EthNetworks(String domain, String extension) {
+        this.domain = URI.create("https://" + domain + ".etherscan." + extension + "/api");
+    }
+
+    @Override
+    public @NotNull URI domain() {
+        return domain;
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
new file mode 100644
index 0000000..d36d385
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -0,0 +1,71 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanKeyException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.executor.impl.UrlEthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.manager.impl.FakeRequestQueueManager;
+import io.goodforgod.api.etherscan.util.BasicUtils;
+import java.util.function.Supplier;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Anton Kurako (GoodforGod)
+ * @since 11.05.2023
+ */
+final class EthScanAPIBuilder implements EtherScanAPI.Builder {
+
+    private static final Supplier<EthHttpClient> DEFAULT_SUPPLIER = UrlEthHttpClient::new;
+    private static final String DEFAULT_KEY = "YourApiKeyToken";
+
+    private String apiKey = DEFAULT_KEY;
+    private EthNetwork ethNetwork = EthNetworks.MAINNET;
+    private RequestQueueManager queueManager = RequestQueueManager.DEFAULT_KEY_QUEUE;
+    private Supplier<EthHttpClient> ethHttpClientSupplier = DEFAULT_SUPPLIER;
+
+    @NotNull
+    @Override
+    public EtherScanAPI.Builder withApiKey(@NotNull String apiKey) {
+        if (BasicUtils.isBlank(apiKey))
+            throw new EtherScanKeyException("API key can not be null or empty");
+
+        this.apiKey = apiKey;
+        if (!DEFAULT_KEY.equals(apiKey)) {
+            queueManager = new FakeRequestQueueManager();
+        }
+        return this;
+    }
+
+    @NotNull
+    @Override
+    public EtherScanAPI.Builder withNetwork(@NotNull EthNetwork network) {
+        this.ethNetwork = network;
+        return this;
+    }
+
+    @NotNull
+    @Override
+    public EtherScanAPI.Builder withNetwork(@NotNull EthNetworks network) {
+        this.ethNetwork = network;
+        return this;
+    }
+
+    @NotNull
+    @Override
+    public EtherScanAPI.Builder withQueue(@NotNull RequestQueueManager queueManager) {
+        this.queueManager = queueManager;
+        return this;
+    }
+
+    @NotNull
+    @Override
+    public EtherScanAPI.Builder withHttpClient(@NotNull Supplier<EthHttpClient> httpClientSupplier) {
+        this.ethHttpClientSupplier = httpClientSupplier;
+        return this;
+    }
+
+    @Override
+    public @NotNull EtherScanAPI build() {
+        return new EtherScanAPIProvider(apiKey, ethNetwork, ethHttpClientSupplier, queueManager);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
new file mode 100644
index 0000000..76dcab7
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -0,0 +1,61 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import java.util.function.Supplier;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan full API Description <a href="https://etherscan.io/apis">...</a>
+ *
+ * @author GoodforGod
+ * @since 10.05.2023
+ */
+public interface EtherScanAPI extends AutoCloseable {
+
+    @NotNull
+    AccountAPI account();
+
+    @NotNull
+    ContractAPI contract();
+
+    @NotNull
+    TransactionAPI txs();
+
+    @NotNull
+    BlockAPI block();
+
+    @NotNull
+    LogsAPI logs();
+
+    @NotNull
+    ProxyAPI proxy();
+
+    @NotNull
+    StatisticAPI stats();
+
+    static Builder builder() {
+        return new EthScanAPIBuilder();
+    }
+
+    interface Builder {
+
+        @NotNull
+        Builder withApiKey(@NotNull String apiKey);
+
+        @NotNull
+        Builder withNetwork(@NotNull EthNetwork network);
+
+        @NotNull
+        Builder withNetwork(@NotNull EthNetworks network);
+
+        @NotNull
+        Builder withQueue(@NotNull RequestQueueManager queueManager);
+
+        @NotNull
+        Builder withHttpClient(@NotNull Supplier<EthHttpClient> httpClientSupplier);
+
+        @NotNull
+        EtherScanAPI build();
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
new file mode 100644
index 0000000..0043e37
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
@@ -0,0 +1,89 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import java.util.function.Supplier;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan full API Description <a href="https://etherscan.io/apis">...</a>
+ *
+ * @author GoodforGod
+ * @since 28.10.2018
+ */
+final class EtherScanAPIProvider implements EtherScanAPI {
+
+    private final RequestQueueManager requestQueueManager;
+    private final AccountAPI account;
+    private final BlockAPI block;
+    private final ContractAPI contract;
+    private final LogsAPI logs;
+    private final ProxyAPI proxy;
+    private final StatisticAPI stats;
+    private final TransactionAPI txs;
+
+    EtherScanAPIProvider(String apiKey,
+                         EthNetwork network,
+                         Supplier<EthHttpClient> executorSupplier,
+                         RequestQueueManager queue) {
+        // EtherScan 1request\5sec limit support by queue manager
+        final EthHttpClient executor = executorSupplier.get();
+        final String baseUrl = network.domain() + "?apikey=" + apiKey;
+
+        this.requestQueueManager = queue;
+        this.account = new AccountAPIProvider(queue, baseUrl, executor);
+        this.block = new BlockAPIProvider(queue, baseUrl, executor);
+        this.contract = new ContractAPIProvider(queue, baseUrl, executor);
+        this.logs = new LogsAPIProvider(queue, baseUrl, executor);
+        this.proxy = new ProxyAPIProvider(queue, baseUrl, executor);
+        this.stats = new StatisticAPIProvider(queue, baseUrl, executor);
+        this.txs = new TransactionAPIProvider(queue, baseUrl, executor);
+    }
+
+    @NotNull
+    @Override
+    public AccountAPI account() {
+        return account;
+    }
+
+    @NotNull
+    @Override
+    public ContractAPI contract() {
+        return contract;
+    }
+
+    @NotNull
+    @Override
+    public TransactionAPI txs() {
+        return txs;
+    }
+
+    @NotNull
+    @Override
+    public BlockAPI block() {
+        return block;
+    }
+
+    @NotNull
+    @Override
+    public LogsAPI logs() {
+        return logs;
+    }
+
+    @NotNull
+    @Override
+    public ProxyAPI proxy() {
+        return proxy;
+    }
+
+    @NotNull
+    @Override
+    public StatisticAPI stats() {
+        return stats;
+    }
+
+    @Override
+    public void close() throws Exception {
+        requestQueueManager.close();
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
new file mode 100644
index 0000000..5b834df
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
@@ -0,0 +1,27 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.Log;
+import io.goodforgod.api.etherscan.model.query.LogQuery;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#logs">...</a>
+ *
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public interface LogsAPI {
+
+    /**
+     * alternative to the native eth_getLogs Read at EtherScan API description for full info!
+     *
+     * @param query build log query
+     * @return logs according to query
+     * @throws EtherScanException parent exception class
+     * @see LogQuery
+     */
+    @NotNull
+    List<Log> logs(LogQuery query) throws EtherScanException;
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
new file mode 100644
index 0000000..771d931
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
@@ -0,0 +1,42 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.Log;
+import io.goodforgod.api.etherscan.model.query.LogQuery;
+import io.goodforgod.api.etherscan.model.response.LogResponseTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
+import java.util.Collections;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Logs API Implementation
+ *
+ * @see LogsAPI
+ * @author GoodforGod
+ * @since 28.10.2018
+ */
+final class LogsAPIProvider extends BasicProvider implements LogsAPI {
+
+    private static final String ACT_LOGS_PARAM = ACT_PREFIX + "getLogs";
+
+    LogsAPIProvider(RequestQueueManager queue,
+                    String baseUrl,
+                    EthHttpClient executor) {
+        super(queue, "logs", baseUrl, executor);
+    }
+
+    @NotNull
+    @Override
+    public List<Log> logs(LogQuery query) throws EtherScanException {
+        final String urlParams = ACT_LOGS_PARAM + query.params();
+        final LogResponseTO response = getRequest(urlParams, LogResponseTO.class);
+        BasicUtils.validateTxResponse(response);
+
+        return (BasicUtils.isEmpty(response.getResult()))
+                ? Collections.emptyList()
+                : response.getResult();
+    }
+}
diff --git a/src/main/java/io/api/etherscan/core/IProxyApi.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
similarity index 63%
rename from src/main/java/io/api/etherscan/core/IProxyApi.java
rename to src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
index b7e9f54..0785d13 100644
--- a/src/main/java/io/api/etherscan/core/IProxyApi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
@@ -1,27 +1,27 @@
-package io.api.etherscan.core;
+package io.goodforgod.api.etherscan;
 
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.proxy.BlockProxy;
-import io.api.etherscan.model.proxy.ReceiptProxy;
-import io.api.etherscan.model.proxy.TxProxy;
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
+import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
+import io.goodforgod.api.etherscan.model.proxy.TxProxy;
 import java.math.BigInteger;
 import java.util.Optional;
 import org.jetbrains.annotations.ApiStatus.Experimental;
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions https://etherscan.io/apis#proxy
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#proxy">...</a>
  *
  * @author GoodforGod
  * @since 30.10.2018
  */
-public interface IProxyApi {
+public interface ProxyAPI {
 
     /**
      * Returns the number of most recent block eth_blockNumber
      * 
      * @return last block number
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     long blockNoLast();
 
@@ -30,10 +30,10 @@ public interface IProxyApi {
      * 
      * @param blockNo block number from 0 to last
      * @return optional block result
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<BlockProxy> block(long blockNo) throws ApiException;
+    Optional<BlockProxy> block(long blockNo) throws EtherScanException;
 
     /**
      * Returns information about a uncle by block number eth_getUncleByBlockNumberAndIndex
@@ -41,10 +41,10 @@ public interface IProxyApi {
      * @param blockNo block number from 0 to last
      * @param index   uncle block index
      * @return optional block result
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<BlockProxy> blockUncle(long blockNo, long index) throws ApiException;
+    Optional<BlockProxy> blockUncle(long blockNo, long index) throws EtherScanException;
 
     /**
      * Returns the information about a transaction requested by transaction hash
@@ -52,10 +52,10 @@ public interface IProxyApi {
      * 
      * @param txhash transaction hash
      * @return optional tx result
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<TxProxy> tx(String txhash) throws ApiException;
+    Optional<TxProxy> tx(String txhash) throws EtherScanException;
 
     /**
      * Returns information about a transaction by block number and transaction index position
@@ -64,10 +64,10 @@ public interface IProxyApi {
      * @param blockNo block number from 0 to last
      * @param index   tx index in block
      * @return optional tx result
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<TxProxy> tx(long blockNo, long index) throws ApiException;
+    Optional<TxProxy> tx(long blockNo, long index) throws EtherScanException;
 
     /**
      * Returns the number of transactions in a block from a block matching the given block number
@@ -75,18 +75,18 @@ public interface IProxyApi {
      * 
      * @param blockNo block number from 0 to last
      * @return transaction amount in block
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
-    int txCount(long blockNo) throws ApiException;
+    int txCount(long blockNo) throws EtherScanException;
 
     /**
      * Returns the number of transactions sent from an address eth_getTransactionCount
      * 
      * @param address eth address
      * @return transactions send amount from address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
-    int txSendCount(String address) throws ApiException;
+    int txSendCount(String address) throws EtherScanException;
 
     /**
      * Creates new message call transaction or a contract creation for signed transactions
@@ -94,20 +94,20 @@ public interface IProxyApi {
      * 
      * @param hexEncodedTx encoded hex data to send
      * @return optional string response
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<String> txSendRaw(String hexEncodedTx) throws ApiException;
+    Optional<String> txSendRaw(String hexEncodedTx) throws EtherScanException;
 
     /**
      * Returns the receipt of a transaction by transaction hash eth_getTransactionReceipt
      * 
      * @param txhash transaction hash
      * @return optional tx receipt
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<ReceiptProxy> txReceipt(String txhash) throws ApiException;
+    Optional<ReceiptProxy> txReceipt(String txhash) throws EtherScanException;
 
     /**
      * Executes a new message call immediately without creating a transaction on the block chain
@@ -116,20 +116,20 @@ public interface IProxyApi {
      * @param address to call
      * @param data    data to call address
      * @return optional the return value of executed contract.
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<String> call(String address, String data) throws ApiException;
+    Optional<String> call(String address, String data) throws EtherScanException;
 
     /**
      * Returns code at a given address eth_getCode
      * 
      * @param address get code from
      * @return optional the code from the given address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<String> code(String address) throws ApiException;
+    Optional<String> code(String address) throws EtherScanException;
 
     /**
      * (**experimental) Returns the value from a storage position at a given address eth_getStorageAt
@@ -137,20 +137,20 @@ public interface IProxyApi {
      * @param address  to get storage
      * @param position storage position
      * @return optional the value at this storage position
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @Experimental
     @NotNull
-    Optional<String> storageAt(String address, long position) throws ApiException;
+    Optional<String> storageAt(String address, long position) throws EtherScanException;
 
     /**
      * Returns the current price per gas in wei eth_gasPrice
      * 
      * @return estimated gas price
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    BigInteger gasPrice() throws ApiException;
+    BigInteger gasPrice() throws EtherScanException;
 
     /**
      * Makes a call or transaction, which won't be added to the blockchain and returns the used gas,
@@ -158,11 +158,11 @@ public interface IProxyApi {
      * 
      * @param hexData data to calc gas usage for
      * @return estimated gas usage
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    BigInteger gasEstimated(String hexData) throws ApiException;
+    BigInteger gasEstimated(String hexData) throws EtherScanException;
 
     @NotNull
-    BigInteger gasEstimated() throws ApiException;
+    BigInteger gasEstimated() throws EtherScanException;
 }
diff --git a/src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
similarity index 75%
rename from src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java
rename to src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index f456186..1239294 100644
--- a/src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -1,19 +1,18 @@
-package io.api.etherscan.core.impl;
-
-import io.api.etherscan.core.IProxyApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.error.InvalidDataHexException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.proxy.BlockProxy;
-import io.api.etherscan.model.proxy.ReceiptProxy;
-import io.api.etherscan.model.proxy.TxProxy;
-import io.api.etherscan.model.proxy.utility.BlockProxyTO;
-import io.api.etherscan.model.proxy.utility.StringProxyTO;
-import io.api.etherscan.model.proxy.utility.TxInfoProxyTO;
-import io.api.etherscan.model.proxy.utility.TxProxyTO;
-import io.api.etherscan.util.BasicUtils;
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidDataHexException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
+import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
+import io.goodforgod.api.etherscan.model.proxy.TxProxy;
+import io.goodforgod.api.etherscan.model.proxy.utility.BlockProxyTO;
+import io.goodforgod.api.etherscan.model.proxy.utility.StringProxyTO;
+import io.goodforgod.api.etherscan.model.proxy.utility.TxInfoProxyTO;
+import io.goodforgod.api.etherscan.model.proxy.utility.TxProxyTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.util.Optional;
 import java.util.regex.Pattern;
@@ -22,11 +21,11 @@
 /**
  * Proxy API Implementation
  *
- * @see IProxyApi
+ * @see ProxyAPI
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class ProxyApiProvider extends BasicProvider implements IProxyApi {
+final class ProxyAPIProvider extends BasicProvider implements ProxyAPI {
 
     private static final String ACT_BLOCKNO_PARAM = ACT_PREFIX + "eth_blockNumber";
     private static final String ACT_BY_BLOCKNO_PARAM = ACT_PREFIX + "eth_getBlockByNumber";
@@ -57,14 +56,14 @@ public class ProxyApiProvider extends BasicProvider implements IProxyApi {
 
     private static final Pattern EMPTY_HEX = Pattern.compile("0x0+");
 
-    ProxyApiProvider(final IQueueManager queue,
+    ProxyAPIProvider(final RequestQueueManager queue,
                      final String baseUrl,
-                     final IHttpExecutor executor) {
+                     final EthHttpClient executor) {
         super(queue, "proxy", baseUrl, executor);
     }
 
     @Override
-    public long blockNoLast() throws ApiException {
+    public long blockNoLast() throws EtherScanException {
         final StringProxyTO response = getRequest(ACT_BLOCKNO_PARAM, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
                 ? -1
@@ -73,7 +72,7 @@ public long blockNoLast() throws ApiException {
 
     @NotNull
     @Override
-    public Optional<BlockProxy> block(final long blockNo) throws ApiException {
+    public Optional<BlockProxy> block(long blockNo) throws EtherScanException {
         final long compBlockNo = BasicUtils.compensateMinBlock(blockNo);
 
         final String urlParams = ACT_BY_BLOCKNO_PARAM + TAG_PARAM + compBlockNo + BOOLEAN_PARAM;
@@ -83,7 +82,7 @@ public Optional<BlockProxy> block(final long blockNo) throws ApiException {
 
     @NotNull
     @Override
-    public Optional<BlockProxy> blockUncle(final long blockNo, final long index) throws ApiException {
+    public Optional<BlockProxy> blockUncle(long blockNo, long index) throws EtherScanException {
         final long compBlockNo = BasicUtils.compensateMinBlock(blockNo);
         final long compIndex = BasicUtils.compensateMinBlock(index);
 
@@ -95,7 +94,7 @@ public Optional<BlockProxy> blockUncle(final long blockNo, final long index) thr
 
     @NotNull
     @Override
-    public Optional<TxProxy> tx(final String txhash) throws ApiException {
+    public Optional<TxProxy> tx(String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_BY_HASH_PARAM + TXHASH_PARAM + txhash;
@@ -105,7 +104,7 @@ public Optional<TxProxy> tx(final String txhash) throws ApiException {
 
     @NotNull
     @Override
-    public Optional<TxProxy> tx(final long blockNo, final long index) throws ApiException {
+    public Optional<TxProxy> tx(long blockNo, long index) throws EtherScanException {
         final long compBlockNo = BasicUtils.compensateMinBlock(blockNo);
         final long compIndex = (index < 1)
                 ? 1
@@ -118,7 +117,7 @@ public Optional<TxProxy> tx(final long blockNo, final long index) throws ApiExce
     }
 
     @Override
-    public int txCount(final long blockNo) throws ApiException {
+    public int txCount(long blockNo) throws EtherScanException {
         final long compensatedBlockNo = BasicUtils.compensateMinBlock(blockNo);
         final String urlParams = ACT_BLOCKTX_COUNT_PARAM + TAG_PARAM + "0x" + Long.toHexString(compensatedBlockNo);
         final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
@@ -126,7 +125,7 @@ public int txCount(final long blockNo) throws ApiException {
     }
 
     @Override
-    public int txSendCount(final String address) throws ApiException {
+    public int txSendCount(String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_TX_COUNT_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
@@ -136,14 +135,14 @@ public int txSendCount(final String address) throws ApiException {
 
     @Override
     @NotNull
-    public Optional<String> txSendRaw(final String hexEncodedTx) throws ApiException {
+    public Optional<String> txSendRaw(String hexEncodedTx) throws EtherScanException {
         if (BasicUtils.isNotHex(hexEncodedTx))
-            throw new InvalidDataHexException("Data is not encoded in hex format - " + hexEncodedTx);
+            throw new EtherScanInvalidDataHexException("Data is not encoded in hex format - " + hexEncodedTx);
 
         final String urlParams = ACT_SEND_RAW_TX_PARAM + HEX_PARAM + hexEncodedTx;
         final StringProxyTO response = postRequest(urlParams, "", StringProxyTO.class);
         if (response.getError() != null)
-            throw new EtherScanException("Error occurred with code " + response.getError().getCode()
+            throw new EtherScanResponseException("Error occurred with code " + response.getError().getCode()
                     + " with message " + response.getError().getMessage()
                     + ", error id " + response.getId() + ", jsonRPC " + response.getJsonrpc());
 
@@ -152,7 +151,7 @@ public Optional<String> txSendRaw(final String hexEncodedTx) throws ApiException
 
     @NotNull
     @Override
-    public Optional<ReceiptProxy> txReceipt(final String txhash) throws ApiException {
+    public Optional<ReceiptProxy> txReceipt(String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_RECEIPT_PARAM + TXHASH_PARAM + txhash;
@@ -162,10 +161,10 @@ public Optional<ReceiptProxy> txReceipt(final String txhash) throws ApiException
 
     @NotNull
     @Override
-    public Optional<String> call(final String address, final String data) throws ApiException {
+    public Optional<String> call(String address, String data) throws EtherScanException {
         BasicUtils.validateAddress(address);
         if (BasicUtils.isNotHex(data))
-            throw new InvalidDataHexException("Data is not hex encoded.");
+            throw new EtherScanInvalidDataHexException("Data is not hex encoded.");
 
         final String urlParams = ACT_CALL_PARAM + TO_PARAM + address + DATA_PARAM + data + TAG_LAST_PARAM;
         final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
@@ -174,7 +173,7 @@ public Optional<String> call(final String address, final String data) throws Api
 
     @NotNull
     @Override
-    public Optional<String> code(final String address) throws ApiException {
+    public Optional<String> code(String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_CODE_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
@@ -184,7 +183,7 @@ public Optional<String> code(final String address) throws ApiException {
 
     @NotNull
     @Override
-    public Optional<String> storageAt(final String address, final long position) throws ApiException {
+    public Optional<String> storageAt(String address, long position) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final long compPosition = BasicUtils.compensateMinBlock(position);
 
@@ -197,7 +196,7 @@ public Optional<String> storageAt(final String address, final long position) thr
 
     @NotNull
     @Override
-    public BigInteger gasPrice() throws ApiException {
+    public BigInteger gasPrice() throws EtherScanException {
         final StringProxyTO response = getRequest(ACT_GASPRICE_PARAM, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
                 ? BigInteger.valueOf(-1)
@@ -206,15 +205,15 @@ public BigInteger gasPrice() throws ApiException {
 
     @NotNull
     @Override
-    public BigInteger gasEstimated() throws ApiException {
+    public BigInteger gasEstimated() throws EtherScanException {
         return gasEstimated("606060405260728060106000396000f360606040526000");
     }
 
     @NotNull
     @Override
-    public BigInteger gasEstimated(final String hexData) throws ApiException {
+    public BigInteger gasEstimated(String hexData) throws EtherScanException {
         if (!BasicUtils.isEmpty(hexData) && BasicUtils.isNotHex(hexData))
-            throw new InvalidDataHexException("Data is not in hex format.");
+            throw new EtherScanInvalidDataHexException("Data is not in hex format.");
 
         final String urlParams = ACT_ESTIMATEGAS_PARAM + DATA_PARAM + hexData + GAS_PARAM + "2000000000000000";
         final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
new file mode 100644
index 0000000..314f73e
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
@@ -0,0 +1,44 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.Price;
+import io.goodforgod.api.etherscan.model.Supply;
+import java.math.BigInteger;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#stats">...</a>
+ *
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public interface StatisticAPI {
+
+    /**
+     * ERC20 token total Supply
+     * 
+     * @param contract contract address
+     * @return token supply for specified contract
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    BigInteger supply(String contract) throws EtherScanException;
+
+    /**
+     * Eth total supply
+     * 
+     * @return total ETH supply for moment
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    Supply supply() throws EtherScanException;
+
+    /**
+     * Eth last USD and BTC price
+     * 
+     * @return last usd/btc price for ETH
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    Price lastPrice() throws EtherScanException;
+}
diff --git a/src/main/java/io/api/etherscan/core/impl/StatisticApiProvider.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
similarity index 54%
rename from src/main/java/io/api/etherscan/core/impl/StatisticApiProvider.java
rename to src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
index a14119a..ee4bdaa 100644
--- a/src/main/java/io/api/etherscan/core/impl/StatisticApiProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
@@ -1,26 +1,25 @@
-package io.api.etherscan.core.impl;
+package io.goodforgod.api.etherscan;
 
-import io.api.etherscan.core.IStatisticApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.Price;
-import io.api.etherscan.model.Supply;
-import io.api.etherscan.model.utility.PriceResponseTO;
-import io.api.etherscan.model.utility.StringResponseTO;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.Price;
+import io.goodforgod.api.etherscan.model.Supply;
+import io.goodforgod.api.etherscan.model.response.PriceResponseTO;
+import io.goodforgod.api.etherscan.model.response.StringResponseTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import org.jetbrains.annotations.NotNull;
 
 /**
  * Statistic API Implementation
  *
- * @see IStatisticApi
+ * @see StatisticAPI
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class StatisticApiProvider extends BasicProvider implements IStatisticApi {
+final class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
 
     private static final String ACT_SUPPLY_PARAM = ACT_PREFIX + "ethsupply";
     private static final String ACT_TOKEN_SUPPLY_PARAM = ACT_PREFIX + "tokensupply";
@@ -28,41 +27,41 @@ public class StatisticApiProvider extends BasicProvider implements IStatisticApi
 
     private static final String CONTRACT_ADDRESS_PARAM = "&contractaddress=";
 
-    StatisticApiProvider(final IQueueManager queue,
+    StatisticAPIProvider(final RequestQueueManager queue,
                          final String baseUrl,
-                         final IHttpExecutor executor) {
+                         final EthHttpClient executor) {
         super(queue, "stats", baseUrl, executor);
     }
 
     @NotNull
     @Override
-    public Supply supply() throws ApiException {
+    public Supply supply() throws EtherScanException {
         final StringResponseTO response = getRequest(ACT_SUPPLY_PARAM, StringResponseTO.class);
         if (response.getStatus() != 1)
-            throw new EtherScanException(response);
+            throw new EtherScanResponseException(response);
 
         return new Supply(new BigInteger(response.getResult()));
     }
 
     @NotNull
     @Override
-    public BigInteger supply(final String contract) throws ApiException {
+    public BigInteger supply(String contract) throws EtherScanException {
         BasicUtils.validateAddress(contract);
 
         final String urlParams = ACT_TOKEN_SUPPLY_PARAM + CONTRACT_ADDRESS_PARAM + contract;
         final StringResponseTO response = getRequest(urlParams, StringResponseTO.class);
         if (response.getStatus() != 1)
-            throw new EtherScanException(response);
+            throw new EtherScanResponseException(response);
 
         return new BigInteger(response.getResult());
     }
 
     @NotNull
     @Override
-    public Price lastPrice() throws ApiException {
+    public Price lastPrice() throws EtherScanException {
         final PriceResponseTO response = getRequest(ACT_LASTPRICE_PARAM, PriceResponseTO.class);
         if (response.getStatus() != 1)
-            throw new EtherScanException(response);
+            throw new EtherScanResponseException(response);
 
         return response.getResult();
     }
diff --git a/src/main/java/io/api/etherscan/core/ITransactionApi.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
similarity index 51%
rename from src/main/java/io/api/etherscan/core/ITransactionApi.java
rename to src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
index 4180ff4..6bfc545 100644
--- a/src/main/java/io/api/etherscan/core/ITransactionApi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
@@ -1,35 +1,35 @@
-package io.api.etherscan.core;
+package io.goodforgod.api.etherscan;
 
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.Status;
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.Status;
 import java.util.Optional;
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions https://etherscan.io/apis#transactions
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#transactions">...</a>
  *
  * @author GoodforGod
  * @since 30.10.2018
  */
-public interface ITransactionApi {
+public interface TransactionAPI {
 
     /**
      * Check Contract Execution Status (if there was an error during contract execution)
      * 
      * @param txhash transaction hash
      * @return optional status result
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<Status> execStatus(String txhash) throws ApiException;
+    Optional<Status> statusExec(String txhash) throws EtherScanException;
 
     /**
      * Check Transaction Receipt Status (Only applicable for Post Byzantium fork transactions)
      * 
      * @param txhash transaction hash
      * @return 0 = Fail, 1 = Pass, empty value for pre-byzantium fork
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<Boolean> receiptStatus(String txhash) throws ApiException;
+    Optional<Boolean> statusReceipt(String txhash) throws EtherScanException;
 }
diff --git a/src/main/java/io/api/etherscan/core/impl/TransactionApiProvider.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
similarity index 60%
rename from src/main/java/io/api/etherscan/core/impl/TransactionApiProvider.java
rename to src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
index 1c83bf0..91082a8 100644
--- a/src/main/java/io/api/etherscan/core/impl/TransactionApiProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
@@ -1,13 +1,12 @@
-package io.api.etherscan.core.impl;
-
-import io.api.etherscan.core.ITransactionApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.Status;
-import io.api.etherscan.model.utility.ReceiptStatusResponseTO;
-import io.api.etherscan.model.utility.StatusResponseTO;
-import io.api.etherscan.util.BasicUtils;
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.Status;
+import io.goodforgod.api.etherscan.model.response.ReceiptStatusResponseTO;
+import io.goodforgod.api.etherscan.model.response.StatusResponseTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.util.Optional;
 import org.jetbrains.annotations.NotNull;
 
@@ -15,25 +14,25 @@
  * Transaction API Implementation
  *
  * @author GoodforGod
- * @see ITransactionApi
+ * @see TransactionAPI
  * @since 28.10.2018
  */
-public class TransactionApiProvider extends BasicProvider implements ITransactionApi {
+final class TransactionAPIProvider extends BasicProvider implements TransactionAPI {
 
     private static final String ACT_EXEC_STATUS_PARAM = ACT_PREFIX + "getstatus";
     private static final String ACT_RECEIPT_STATUS_PARAM = ACT_PREFIX + "gettxreceiptstatus";
 
     private static final String TXHASH_PARAM = "&txhash=";
 
-    TransactionApiProvider(final IQueueManager queue,
-                           final String baseUrl,
-                           final IHttpExecutor executor) {
+    TransactionAPIProvider(RequestQueueManager queue,
+                           String baseUrl,
+                           EthHttpClient executor) {
         super(queue, "transaction", baseUrl, executor);
     }
 
     @NotNull
     @Override
-    public Optional<Status> execStatus(final String txhash) throws ApiException {
+    public Optional<Status> statusExec(String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_EXEC_STATUS_PARAM + TXHASH_PARAM + txhash;
@@ -45,7 +44,7 @@ public Optional<Status> execStatus(final String txhash) throws ApiException {
 
     @NotNull
     @Override
-    public Optional<Boolean> receiptStatus(final String txhash) throws ApiException {
+    public Optional<Boolean> statusReceipt(String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_RECEIPT_STATUS_PARAM + TXHASH_PARAM + txhash;
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/ErtherScanLogQueryException.java b/src/main/java/io/goodforgod/api/etherscan/error/ErtherScanLogQueryException.java
new file mode 100644
index 0000000..b39dcee
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/ErtherScanLogQueryException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 31.10.2018
+ */
+public class ErtherScanLogQueryException extends EtherScanException {
+
+    public ErtherScanLogQueryException(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionException.java
new file mode 100644
index 0000000..731592c
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionException.java
@@ -0,0 +1,16 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class EtherScanConnectionException extends EtherScanException {
+
+    public EtherScanConnectionException(String message) {
+        super(message);
+    }
+
+    public EtherScanConnectionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanException.java
new file mode 100644
index 0000000..67cc3bb
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanException.java
@@ -0,0 +1,16 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public class EtherScanException extends RuntimeException {
+
+    public EtherScanException(String message) {
+        super(message);
+    }
+
+    public EtherScanException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidAddressException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidAddressException.java
new file mode 100644
index 0000000..ff12e3c
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidAddressException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class EtherScanInvalidAddressException extends EtherScanException {
+
+    public EtherScanInvalidAddressException(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidDataHexException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidDataHexException.java
new file mode 100644
index 0000000..b5b5f2d
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidDataHexException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 02.11.2018
+ */
+public class EtherScanInvalidDataHexException extends EtherScanException {
+
+    public EtherScanInvalidDataHexException(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidTxHashException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidTxHashException.java
new file mode 100644
index 0000000..33be4ad
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanInvalidTxHashException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 02.11.2018
+ */
+public class EtherScanInvalidTxHashException extends EtherScanException {
+
+    public EtherScanInvalidTxHashException(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanKeyException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanKeyException.java
new file mode 100644
index 0000000..f9e4aa8
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanKeyException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 05.11.2018
+ */
+public class EtherScanKeyException extends EtherScanException {
+
+    public EtherScanKeyException(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/io/api/etherscan/error/ParseException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanParseException.java
similarity index 52%
rename from src/main/java/io/api/etherscan/error/ParseException.java
rename to src/main/java/io/goodforgod/api/etherscan/error/EtherScanParseException.java
index 5dc6199..87116ab 100644
--- a/src/main/java/io/api/etherscan/error/ParseException.java
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanParseException.java
@@ -1,14 +1,14 @@
-package io.api.etherscan.error;
+package io.goodforgod.api.etherscan.error;
 
 /**
  * @author GoodforGod
  * @since 29.10.2018
  */
-public class ParseException extends ApiException {
+public class EtherScanParseException extends EtherScanException {
 
     private final String json;
 
-    public ParseException(String message, Throwable cause, String json) {
+    public EtherScanParseException(String message, Throwable cause, String json) {
         super(message, cause);
         this.json = json;
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanRateLimitException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanRateLimitException.java
new file mode 100644
index 0000000..eefb1ea
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanRateLimitException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author iSnow
+ * @since 2020-10-06
+ */
+public class EtherScanRateLimitException extends EtherScanException {
+
+    public EtherScanRateLimitException(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java
new file mode 100644
index 0000000..21da798
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java
@@ -0,0 +1,23 @@
+package io.goodforgod.api.etherscan.error;
+
+import io.goodforgod.api.etherscan.model.response.BaseResponseTO;
+import io.goodforgod.api.etherscan.model.response.StringResponseTO;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class EtherScanResponseException extends EtherScanException {
+
+    public EtherScanResponseException(BaseResponseTO response) {
+        this(response.getMessage() + ", with status: " + response.getStatus());
+    }
+
+    public EtherScanResponseException(StringResponseTO response) {
+        this(response.getResult() + ", with status: " + response.getStatus() + ", with message: " + response.getMessage());
+    }
+
+    public EtherScanResponseException(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java
new file mode 100644
index 0000000..7734139
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 12.11.2018
+ */
+public class EtherScanTimeoutException extends EtherScanConnectionException {
+
+    public EtherScanTimeoutException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/io/api/etherscan/executor/IHttpExecutor.java b/src/main/java/io/goodforgod/api/etherscan/executor/EthHttpClient.java
similarity index 84%
rename from src/main/java/io/api/etherscan/executor/IHttpExecutor.java
rename to src/main/java/io/goodforgod/api/etherscan/executor/EthHttpClient.java
index 0c80282..4edc507 100644
--- a/src/main/java/io/api/etherscan/executor/IHttpExecutor.java
+++ b/src/main/java/io/goodforgod/api/etherscan/executor/EthHttpClient.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.executor;
+package io.goodforgod.api.etherscan.executor;
 
 /**
  * Http Client interface
@@ -6,7 +6,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-public interface IHttpExecutor {
+public interface EthHttpClient {
 
     /**
      * Performs a Http GET request
diff --git a/src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java b/src/main/java/io/goodforgod/api/etherscan/executor/impl/UrlEthHttpClient.java
similarity index 66%
rename from src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java
rename to src/main/java/io/goodforgod/api/etherscan/executor/impl/UrlEthHttpClient.java
index 49e7fee..ac05125 100644
--- a/src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java
+++ b/src/main/java/io/goodforgod/api/etherscan/executor/impl/UrlEthHttpClient.java
@@ -1,11 +1,11 @@
-package io.api.etherscan.executor.impl;
+package io.goodforgod.api.etherscan.executor.impl;
 
 import static java.net.HttpURLConnection.*;
 
-import io.api.etherscan.error.ApiTimeoutException;
-import io.api.etherscan.error.ConnectionException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.error.EtherScanConnectionException;
+import io.goodforgod.api.etherscan.error.EtherScanTimeoutException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -14,6 +14,8 @@
 import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.zip.GZIPInputStream;
@@ -23,15 +25,15 @@
  * Http client implementation
  *
  * @author GoodforGod
- * @see IHttpExecutor
+ * @see EthHttpClient
  * @since 28.10.2018
  */
-public class HttpExecutor implements IHttpExecutor {
+public final class UrlEthHttpClient implements EthHttpClient {
 
     private static final Map<String, String> DEFAULT_HEADERS = new HashMap<>();
 
-    private static final int CONNECT_TIMEOUT = 8000;
-    private static final int READ_TIMEOUT = 0;
+    private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(8);
+    private static final Duration DEFAULT_READ_TIMEOUT = Duration.ZERO;
 
     static {
         DEFAULT_HEADERS.put("Accept-Language", "en");
@@ -44,15 +46,15 @@ public class HttpExecutor implements IHttpExecutor {
     private final int connectTimeout;
     private final int readTimeout;
 
-    public HttpExecutor() {
-        this(CONNECT_TIMEOUT);
+    public UrlEthHttpClient() {
+        this(DEFAULT_CONNECT_TIMEOUT);
     }
 
-    public HttpExecutor(final int connectTimeout) {
-        this(connectTimeout, READ_TIMEOUT);
+    public UrlEthHttpClient(Duration connectTimeout) {
+        this(connectTimeout, DEFAULT_READ_TIMEOUT);
     }
 
-    public HttpExecutor(final int connectTimeout, final int readTimeout) {
+    public UrlEthHttpClient(Duration connectTimeout, Duration readTimeout) {
         this(connectTimeout, readTimeout, DEFAULT_HEADERS);
     }
 
@@ -61,12 +63,12 @@ public HttpExecutor(final int connectTimeout, final int readTimeout) {
      * @param readTimeout    custom read timeout in millis
      * @param headers        custom HTTP headers
      */
-    public HttpExecutor(final int connectTimeout,
-                        final int readTimeout,
-                        final Map<String, String> headers) {
-        this.connectTimeout = Math.max(connectTimeout, 0);
-        this.readTimeout = Math.max(readTimeout, 0);
-        this.headers = headers;
+    public UrlEthHttpClient(Duration connectTimeout,
+                            Duration readTimeout,
+                            Map<String, String> headers) {
+        this.connectTimeout = Math.toIntExact(connectTimeout.toMillis());
+        this.readTimeout = Math.toIntExact(readTimeout.toMillis());
+        this.headers = Collections.unmodifiableMap(headers);
     }
 
     private HttpURLConnection buildConnection(String urlAsString, String method) throws IOException {
@@ -87,23 +89,23 @@ public String get(final String urlAsString) {
             if (status == HTTP_MOVED_TEMP || status == HTTP_MOVED_PERM) {
                 return get(connection.getHeaderField("Location"));
             } else if ((status >= HTTP_BAD_REQUEST) && (status < HTTP_INTERNAL_ERROR)) {
-                throw new ConnectionException("Protocol error: " + connection.getResponseMessage());
+                throw new EtherScanConnectionException("Protocol error: " + connection.getResponseMessage());
             } else if (status >= HTTP_INTERNAL_ERROR) {
-                throw new ConnectionException("Server error: " + connection.getResponseMessage());
+                throw new EtherScanConnectionException("Server error: " + connection.getResponseMessage());
             }
 
             final String data = readData(connection);
             connection.disconnect();
             return data;
         } catch (SocketTimeoutException e) {
-            throw new ApiTimeoutException("Timeout: Could not establish connection for " + connectTimeout + " millis", e);
+            throw new EtherScanTimeoutException("Timeout: Could not establish connection for " + connectTimeout + " millis", e);
         } catch (Exception e) {
-            throw new ConnectionException(e.getMessage(), e);
+            throw new EtherScanConnectionException(e.getMessage(), e);
         }
     }
 
     @Override
-    public String post(final String urlAsString, final String dataToPost) {
+    public String post(String urlAsString, String dataToPost) {
         try {
             final HttpURLConnection connection = buildConnection(urlAsString, "POST");
             final String contentLength = (BasicUtils.isBlank(dataToPost))
@@ -123,22 +125,22 @@ public String post(final String urlAsString, final String dataToPost) {
             if (status == HTTP_MOVED_TEMP || status == HTTP_MOVED_PERM) {
                 return post(connection.getHeaderField("Location"), dataToPost);
             } else if ((status >= HTTP_BAD_REQUEST) && (status < HTTP_INTERNAL_ERROR)) {
-                throw new ConnectionException("Protocol error: " + connection.getResponseMessage());
+                throw new EtherScanConnectionException("Protocol error: " + connection.getResponseMessage());
             } else if (status >= HTTP_INTERNAL_ERROR) {
-                throw new ConnectionException("Server error: " + connection.getResponseMessage());
+                throw new EtherScanConnectionException("Server error: " + connection.getResponseMessage());
             }
 
             final String data = readData(connection);
             connection.disconnect();
             return data;
         } catch (SocketTimeoutException e) {
-            throw new ApiTimeoutException("Timeout: Could not establish connection for " + connectTimeout + " millis", e);
+            throw new EtherScanTimeoutException("Timeout: Could not establish connection for " + connectTimeout + " millis", e);
         } catch (Exception e) {
-            throw new ConnectionException(e.getMessage(), e);
+            throw new EtherScanConnectionException(e.getMessage(), e);
         }
     }
 
-    private String readData(final HttpURLConnection connection) throws IOException {
+    private String readData(HttpURLConnection connection) throws IOException {
         final StringBuilder content = new StringBuilder();
         try (BufferedReader in = new BufferedReader(getStreamReader(connection))) {
             String inputLine;
@@ -149,7 +151,7 @@ private String readData(final HttpURLConnection connection) throws IOException {
         return content.toString();
     }
 
-    private InputStreamReader getStreamReader(final HttpURLConnection connection) throws IOException {
+    private InputStreamReader getStreamReader(HttpURLConnection connection) throws IOException {
         switch (String.valueOf(connection.getContentEncoding())) {
             case "gzip":
                 return new InputStreamReader(new GZIPInputStream(connection.getInputStream()), StandardCharsets.UTF_8);
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
new file mode 100644
index 0000000..7472c3f
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -0,0 +1,24 @@
+package io.goodforgod.api.etherscan.manager;
+
+import io.goodforgod.api.etherscan.manager.impl.SemaphoreRequestQueueManager;
+import java.time.Duration;
+
+/**
+ * Queue manager to support API limits (EtherScan 5request\sec limit) Managers grants turn if the
+ * limit is not exhausted And resets queue each set period
+ *
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public interface RequestQueueManager extends AutoCloseable {
+
+    RequestQueueManager DEFAULT_KEY_QUEUE = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5050L),
+            Duration.ofMillis(5050L), 0);
+    RequestQueueManager PERSONAL_KEY_QUEUE = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1050L),
+            Duration.ofMillis(1050L), 5);
+
+    /**
+     * Waits in queue for chance to take turn
+     */
+    void takeTurn();
+}
diff --git a/src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java
similarity index 65%
rename from src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java
rename to src/main/java/io/goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java
index 620244c..626b4c1 100644
--- a/src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.manager.impl;
+package io.goodforgod.api.etherscan.manager.impl;
 
-import io.api.etherscan.manager.IQueueManager;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 
 /**
  * Fake queue manager, always give turns, when you have no limits
@@ -8,7 +8,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-public class FakeQueueManager implements IQueueManager {
+public final class FakeRequestQueueManager implements RequestQueueManager {
 
     @Override
     public void takeTurn() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
new file mode 100644
index 0000000..cfd745f
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
@@ -0,0 +1,53 @@
+package io.goodforgod.api.etherscan.manager.impl;
+
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import java.time.Duration;
+import java.util.concurrent.*;
+
+/**
+ * Queue Semaphore implementation with size and reset time as params
+ * 
+ * @see RequestQueueManager
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public final class SemaphoreRequestQueueManager implements RequestQueueManager, AutoCloseable {
+
+    private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
+    private final Semaphore semaphore;
+    private final long queueResetTimeInMillis;
+
+    public SemaphoreRequestQueueManager(int size, Duration resetIn) {
+        this(size, resetIn, resetIn);
+    }
+
+    public SemaphoreRequestQueueManager(int size, Duration resetIn, Duration delayIn) {
+        this(size, resetIn, delayIn, size);
+    }
+
+    public SemaphoreRequestQueueManager(int size, Duration queueResetTimeIn, Duration delayIn, int initialSize) {
+        this.semaphore = new Semaphore(initialSize);
+        this.queueResetTimeInMillis = queueResetTimeIn.toMillis();
+        this.executorService.scheduleAtFixedRate(releaseLocks(size + 1), delayIn.toMillis(), queueResetTimeInMillis,
+                TimeUnit.MILLISECONDS);
+    }
+
+    @SuppressWarnings("java:S899")
+    @Override
+    public void takeTurn() {
+        try {
+            semaphore.tryAcquire(queueResetTimeInMillis, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    private Runnable releaseLocks(int toRelease) {
+        return () -> semaphore.release(toRelease);
+    }
+
+    @Override
+    public void close() {
+        executorService.shutdown();
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/Abi.java b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
similarity index 94%
rename from src/main/java/io/api/etherscan/model/Abi.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Abi.java
index 880e6a0..b575c56 100644
--- a/src/main/java/io/api/etherscan/model/Abi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/Balance.java b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
similarity index 94%
rename from src/main/java/io/api/etherscan/model/Balance.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Balance.java
index ed6d6c5..d147a2c 100644
--- a/src/main/java/io/api/etherscan/model/Balance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
-import io.api.etherscan.model.utility.BalanceTO;
+import io.goodforgod.api.etherscan.model.response.BalanceTO;
 import java.math.BigInteger;
 import java.util.Objects;
 
diff --git a/src/main/java/io/api/etherscan/model/BaseTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
similarity index 97%
rename from src/main/java/io/api/etherscan/model/BaseTx.java
rename to src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
index 3942d14..1fb53e1 100644
--- a/src/main/java/io/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import com.google.gson.annotations.Expose;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
diff --git a/src/main/java/io/api/etherscan/model/Block.java b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
similarity index 94%
rename from src/main/java/io/api/etherscan/model/Block.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Block.java
index f5e8b6a..8b652bb 100644
--- a/src/main/java/io/api/etherscan/model/Block.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import com.google.gson.annotations.Expose;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
new file mode 100644
index 0000000..34f8f30
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
@@ -0,0 +1,128 @@
+package io.goodforgod.api.etherscan.model;
+
+import io.goodforgod.api.etherscan.util.BasicUtils;
+
+import java.math.BigInteger;
+import java.util.List;
+
+/**
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public class BlockUncle extends Block {
+
+    public static class Uncle {
+
+        private String miner;
+        private BigInteger blockreward;
+        private int unclePosition;
+
+        // <editor-fold desc="Getters">
+        public String getMiner() {
+            return miner;
+        }
+
+        public BigInteger getBlockreward() {
+            return blockreward;
+        }
+
+        public int getUnclePosition() {
+            return unclePosition;
+        }
+        // </editor-fold>
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Uncle uncle = (Uncle) o;
+            if (unclePosition != uncle.unclePosition)
+                return false;
+            if (miner != null
+                    ? !miner.equals(uncle.miner)
+                    : uncle.miner != null)
+                return false;
+            return blockreward != null
+                    ? blockreward.equals(uncle.blockreward)
+                    : uncle.blockreward == null;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = miner != null
+                    ? miner.hashCode()
+                    : 0;
+            result = 31 * result + (blockreward != null
+                    ? blockreward.hashCode()
+                    : 0);
+            result = 31 * result + unclePosition;
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "Uncle{" +
+                    "miner='" + miner + '\'' +
+                    ", blockreward=" + blockreward +
+                    ", unclePosition=" + unclePosition +
+                    '}';
+        }
+    }
+
+    private String blockMiner;
+    private List<Uncle> uncles;
+    private String uncleInclusionReward;
+
+    // <editor-fold desc="Getters">
+    public boolean isEmpty() {
+        return getBlockNumber() == 0 && getBlockReward() == null
+                && getTimeStamp() == null
+                && BasicUtils.isEmpty(blockMiner);
+    }
+
+    public String getBlockMiner() {
+        return blockMiner;
+    }
+
+    public List<Uncle> getUncles() {
+        return uncles;
+    }
+
+    public String getUncleInclusionReward() {
+        return uncleInclusionReward;
+    }
+    // </editor-fold>
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+
+        BlockUncle that = (BlockUncle) o;
+
+        return getBlockNumber() != 0 && getBlockNumber() == that.getBlockNumber();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = (int) (31 * result + getBlockNumber());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "UncleBlock{" +
+                "blockMiner='" + blockMiner + '\'' +
+                ", uncles=" + uncles +
+                ", uncleInclusionReward='" + uncleInclusionReward + '\'' +
+                '}';
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
similarity index 98%
rename from src/main/java/io/api/etherscan/model/Log.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Log.java
index 595122b..cc22b66 100644
--- a/src/main/java/io/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import com.google.gson.annotations.Expose;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
diff --git a/src/main/java/io/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
similarity index 98%
rename from src/main/java/io/api/etherscan/model/Price.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Price.java
index fc72ab5..712dbd8 100644
--- a/src/main/java/io/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import com.google.gson.annotations.Expose;
 import java.time.LocalDateTime;
diff --git a/src/main/java/io/api/etherscan/model/Status.java b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
similarity index 96%
rename from src/main/java/io/api/etherscan/model/Status.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Status.java
index 2017cd7..274080a 100644
--- a/src/main/java/io/api/etherscan/model/Status.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import java.util.Objects;
 
diff --git a/src/main/java/io/api/etherscan/model/Supply.java b/src/main/java/io/goodforgod/api/etherscan/model/Supply.java
similarity index 81%
rename from src/main/java/io/api/etherscan/model/Supply.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Supply.java
index f495aaf..80dc7d0 100644
--- a/src/main/java/io/api/etherscan/model/Supply.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Supply.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import java.math.BigInteger;
 
diff --git a/src/main/java/io/api/etherscan/model/TokenBalance.java b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
similarity index 96%
rename from src/main/java/io/api/etherscan/model/TokenBalance.java
rename to src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
index 684738c..d42fd05 100644
--- a/src/main/java/io/api/etherscan/model/TokenBalance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import java.math.BigInteger;
 import java.util.Objects;
diff --git a/src/main/java/io/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
similarity index 96%
rename from src/main/java/io/api/etherscan/model/Tx.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 13b5292..3ab0923 100644
--- a/src/main/java/io/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.util.Objects;
 
diff --git a/src/main/java/io/api/etherscan/model/TxToken.java b/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
similarity index 93%
rename from src/main/java/io/api/etherscan/model/TxToken.java
rename to src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
index c455ffb..9f65d98 100644
--- a/src/main/java/io/api/etherscan/model/TxToken.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
@@ -1,10 +1,10 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 /**
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class TxToken extends BaseTx {
+public class TxERC20 extends BaseTx {
 
     private long nonce;
     private String blockHash;
@@ -56,7 +56,7 @@ public long getConfirmations() {
 
     @Override
     public String toString() {
-        return "TxToken{" +
+        return "TxERC20{" +
                 "nonce=" + nonce +
                 ", blockHash='" + blockHash + '\'' +
                 ", tokenName='" + tokenName + '\'' +
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
new file mode 100644
index 0000000..5b30314
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
@@ -0,0 +1,71 @@
+package io.goodforgod.api.etherscan.model;
+
+/**
+ * @author GoodforGod
+ * @since 28.10.2018
+ */
+public class TxERC721 extends BaseTx {
+
+    private long nonce;
+    private String blockHash;
+    private String tokenName;
+    private String tokenSymbol;
+    private String tokenDecimal;
+    private int transactionIndex;
+    private long gasPrice;
+    private long cumulativeGasUsed;
+    private long confirmations;
+
+    // <editor-fold desc="Getters">
+    public long getNonce() {
+        return nonce;
+    }
+
+    public String getBlockHash() {
+        return blockHash;
+    }
+
+    public String getTokenName() {
+        return tokenName;
+    }
+
+    public String getTokenSymbol() {
+        return tokenSymbol;
+    }
+
+    public String getTokenDecimal() {
+        return tokenDecimal;
+    }
+
+    public int getTransactionIndex() {
+        return transactionIndex;
+    }
+
+    public long getGasPrice() {
+        return gasPrice;
+    }
+
+    public long getCumulativeGasUsed() {
+        return cumulativeGasUsed;
+    }
+
+    public long getConfirmations() {
+        return confirmations;
+    }
+    // </editor-fold>
+
+    @Override
+    public String toString() {
+        return "TxERC721{" +
+                "nonce=" + nonce +
+                ", blockHash='" + blockHash + '\'' +
+                ", tokenName='" + tokenName + '\'' +
+                ", tokenSymbol='" + tokenSymbol + '\'' +
+                ", tokenDecimal='" + tokenDecimal + '\'' +
+                ", transactionIndex=" + transactionIndex +
+                ", gasPrice=" + gasPrice +
+                ", cumulativeGasUsed=" + cumulativeGasUsed +
+                ", confirmations=" + confirmations +
+                "} " + super.toString();
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
similarity index 97%
rename from src/main/java/io/api/etherscan/model/TxInternal.java
rename to src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index 5471268..244e0b7 100644
--- a/src/main/java/io/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import java.util.Objects;
 
diff --git a/src/main/java/io/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
similarity index 96%
rename from src/main/java/io/api/etherscan/model/Wei.java
rename to src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index 0735d90..224a1cf 100644
--- a/src/main/java/io/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import java.math.BigInteger;
 import java.util.Objects;
diff --git a/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
similarity index 98%
rename from src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index 2afbe40..889cc0e 100644
--- a/src/main/java/io/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.model.proxy;
+package io.goodforgod.api.etherscan.model.proxy;
 
 import com.google.gson.annotations.Expose;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
diff --git a/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
similarity index 96%
rename from src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index 1e25dbd..f4f7845 100644
--- a/src/main/java/io/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.model.proxy;
+package io.goodforgod.api.etherscan.model.proxy;
 
 import com.google.gson.annotations.Expose;
-import io.api.etherscan.model.Log;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.model.Log;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 import java.util.List;
 
diff --git a/src/main/java/io/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
similarity index 97%
rename from src/main/java/io/api/etherscan/model/proxy/TxProxy.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index a89f4a8..cf3199b 100644
--- a/src/main/java/io/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.model.proxy;
+package io.goodforgod.api.etherscan.model.proxy;
 
 import com.google.gson.annotations.Expose;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
 
 /**
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/BaseProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
similarity index 86%
rename from src/main/java/io/api/etherscan/model/proxy/utility/BaseProxyTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
index 0291dfe..ef57193 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/BaseProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.proxy.utility;
+package io.goodforgod.api.etherscan.model.proxy.utility;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/BlockProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BlockProxyTO.java
similarity index 63%
rename from src/main/java/io/api/etherscan/model/proxy/utility/BlockProxyTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BlockProxyTO.java
index 2057c89..cf6c16b 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/BlockProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BlockProxyTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.proxy.utility;
+package io.goodforgod.api.etherscan.model.proxy.utility;
 
-import io.api.etherscan.model.proxy.BlockProxy;
+import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/ErrorProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/ErrorProxyTO.java
similarity index 81%
rename from src/main/java/io/api/etherscan/model/proxy/utility/ErrorProxyTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/ErrorProxyTO.java
index a3bc435..9b14cec 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/ErrorProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/ErrorProxyTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.proxy.utility;
+package io.goodforgod.api.etherscan.model.proxy.utility;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/StringProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/StringProxyTO.java
similarity index 77%
rename from src/main/java/io/api/etherscan/model/proxy/utility/StringProxyTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/StringProxyTO.java
index 8d1d08c..489d87b 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/StringProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/StringProxyTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.proxy.utility;
+package io.goodforgod.api.etherscan.model.proxy.utility;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/TxInfoProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
similarity index 63%
rename from src/main/java/io/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
index 3bbe039..208cdbe 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.proxy.utility;
+package io.goodforgod.api.etherscan.model.proxy.utility;
 
-import io.api.etherscan.model.proxy.ReceiptProxy;
+import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/proxy/utility/TxProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxProxyTO.java
similarity index 62%
rename from src/main/java/io/api/etherscan/model/proxy/utility/TxProxyTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxProxyTO.java
index 7e9c9e8..0c084e7 100644
--- a/src/main/java/io/api/etherscan/model/proxy/utility/TxProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxProxyTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.proxy.utility;
+package io.goodforgod.api.etherscan.model.proxy.utility;
 
-import io.api.etherscan.model.proxy.TxProxy;
+import io.goodforgod.api.etherscan.model.proxy.TxProxy;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/query/LogOp.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogOp.java
similarity index 86%
rename from src/main/java/io/api/etherscan/model/query/LogOp.java
rename to src/main/java/io/goodforgod/api/etherscan/model/query/LogOp.java
index 0c0ebee..9136034 100644
--- a/src/main/java/io/api/etherscan/model/query/LogOp.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogOp.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.query;
+package io.goodforgod.api.etherscan.model.query;
 
 /**
  * Part of The Event Log API
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java
new file mode 100644
index 0000000..69e8409
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java
@@ -0,0 +1,51 @@
+package io.goodforgod.api.etherscan.model.query;
+
+import static io.goodforgod.api.etherscan.model.query.LogQueryBuilderImpl.MAX_BLOCK;
+import static io.goodforgod.api.etherscan.model.query.LogQueryBuilderImpl.MIN_BLOCK;
+
+import io.goodforgod.api.etherscan.LogsAPI;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Final builded container for The Event Log API
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#logs">...</a>
+ *
+ * @see LogQueryBuilderImpl
+ * @see LogsAPI
+ * @author GoodforGod
+ * @since 10.05.2023
+ */
+public interface LogQuery {
+
+    @NotNull
+    String params();
+
+    @NotNull
+    static Builder builder(String address) {
+        return new LogQueryBuilderImpl(address, MIN_BLOCK, MAX_BLOCK);
+    }
+
+    interface Builder {
+
+        @NotNull
+        LogQuery.Builder withBlockFrom(long startBlock);
+
+        @NotNull
+        LogQuery.Builder withBlockTo(long endBlock);
+
+        @NotNull
+        LogTopicSingle withTopic(String topic0);
+
+        @NotNull
+        LogTopicTuple withTopic(String topic0, String topic1);
+
+        @NotNull
+        LogTopicTriple withTopic(String topic0, String topic1, String topic2);
+
+        @NotNull
+        LogTopicQuadro withTopic(String topic0, String topic1, String topic2, String topic3);
+
+        @NotNull
+        LogQuery build();
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
new file mode 100644
index 0000000..0d1eb59
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
@@ -0,0 +1,84 @@
+package io.goodforgod.api.etherscan.model.query;
+
+import io.goodforgod.api.etherscan.LogsAPI;
+import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import io.goodforgod.api.etherscan.util.BasicUtils;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Builder for The Event Log API
+ *
+ * @see LogsAPI
+ * @author GoodforGod
+ * @since 31.10.2018
+ */
+final class LogQueryBuilderImpl implements LogQuery.Builder {
+
+    static final long MIN_BLOCK = 0;
+    static final long MAX_BLOCK = 99999999999999999L;
+
+    private final String address;
+    private final long startBlock, endBlock;
+
+    LogQueryBuilderImpl(String address, long startBlock, long endBlock) {
+        this.address = address;
+        this.startBlock = startBlock;
+        this.endBlock = endBlock;
+    }
+
+    @Override
+    public @NotNull LogQuery.Builder withBlockFrom(long startBlock) {
+        return new LogQueryBuilderImpl(this.address, startBlock, this.endBlock);
+    }
+
+    @Override
+    public @NotNull LogQuery.Builder withBlockTo(long endBlock) {
+        return new LogQueryBuilderImpl(this.address, this.startBlock, endBlock);
+    }
+
+    @Override
+    public @NotNull LogTopicSingle withTopic(String topic0) {
+        if (BasicUtils.isNotHex(topic0))
+            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+        return new LogTopicSingle(address, startBlock, endBlock, topic0);
+    }
+
+    @Override
+    public @NotNull LogTopicTuple withTopic(String topic0, String topic1) {
+        if (BasicUtils.isNotHex(topic0))
+            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+        if (BasicUtils.isNotHex(topic1))
+            throw new ErtherScanLogQueryException("topic1 can not be empty or non hex.");
+        return new LogTopicTuple(address, startBlock, endBlock, topic0, topic1);
+    }
+
+    @Override
+    public @NotNull LogTopicTriple withTopic(String topic0, String topic1, String topic2) {
+        if (BasicUtils.isNotHex(topic0))
+            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+        if (BasicUtils.isNotHex(topic1))
+            throw new ErtherScanLogQueryException("topic1 can not be empty or non hex.");
+        if (BasicUtils.isNotHex(topic2))
+            throw new ErtherScanLogQueryException("topic2 can not be empty or non hex.");
+        return new LogTopicTriple(address, startBlock, endBlock, topic0, topic1, topic2);
+    }
+
+    @Override
+    public @NotNull LogTopicQuadro withTopic(String topic0, String topic1, String topic2, String topic3) {
+        if (BasicUtils.isNotHex(topic0))
+            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+        if (BasicUtils.isNotHex(topic1))
+            throw new ErtherScanLogQueryException("topic1 can not be empty or non hex.");
+        if (BasicUtils.isNotHex(topic2))
+            throw new ErtherScanLogQueryException("topic2 can not be empty or non hex.");
+        if (BasicUtils.isNotHex(topic3))
+            throw new ErtherScanLogQueryException("topic3 can not be empty or non hex.");
+
+        return new LogTopicQuadro(address, startBlock, endBlock, topic0, topic1, topic2, topic3);
+    }
+
+    @Override
+    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
+        return new LogQueryImpl("&address=" + this.address + "&fromBlock=" + this.startBlock + "&toBlock=" + this.endBlock);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
new file mode 100644
index 0000000..ef66e72
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
@@ -0,0 +1,30 @@
+package io.goodforgod.api.etherscan.model.query;
+
+import io.goodforgod.api.etherscan.LogsAPI;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Final builded container for The Event Log API
+ * EtherScan - API Descriptions <a href="https://etherscan.io/apis#logs">...</a>
+ *
+ * @see LogQueryBuilderImpl
+ * @see LogsAPI
+ * @author GoodforGod
+ * @since 31.10.2018
+ */
+final class LogQueryImpl implements LogQuery {
+
+    /**
+     * Final request parameter for api call
+     */
+    private final String params;
+
+    LogQueryImpl(String params) {
+        this.params = params;
+    }
+
+    @Override
+    public @NotNull String params() {
+        return params;
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/query/impl/BaseLogQuery.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryParams.java
similarity index 79%
rename from src/main/java/io/api/etherscan/model/query/impl/BaseLogQuery.java
rename to src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryParams.java
index c472f84..ac77ae8 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/BaseLogQuery.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryParams.java
@@ -1,16 +1,18 @@
-package io.api.etherscan.model.query.impl;
+package io.goodforgod.api.etherscan.model.query;
 
-import io.api.etherscan.core.ILogsApi;
+import io.goodforgod.api.etherscan.LogsAPI;
 
 /**
  * Base parameters for The Event Log API builder
  *
- * @see LogQueryBuilder
- * @see ILogsApi
+ * @see LogQueryBuilderImpl
+ * @see LogsAPI
  * @author GoodforGod
  * @since 31.10.2018
  */
-abstract class BaseLogQuery {
+final class LogQueryParams {
+
+    private LogQueryParams() {}
 
     static final String FROM_BLOCK_PARAM = "&fromBlock=";
     static final String TO_BLOCK_PARAM = "&toBlock=";
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicBuilder.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicBuilder.java
new file mode 100644
index 0000000..715f869
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicBuilder.java
@@ -0,0 +1,17 @@
+package io.goodforgod.api.etherscan.model.query;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @see LogTopicSingle
+ * @see LogTopicTuple
+ * @see LogTopicTriple
+ * @see LogTopicQuadro
+ * @author GoodforGod
+ * @since 10.05.2023
+ */
+public interface LogTopicBuilder {
+
+    @NotNull
+    LogQuery build();
+}
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicQuadro.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
similarity index 71%
rename from src/main/java/io/api/etherscan/model/query/impl/LogTopicQuadro.java
rename to src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
index bab5b29..1469f97 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicQuadro.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
@@ -1,19 +1,20 @@
-package io.api.etherscan.model.query.impl;
+package io.goodforgod.api.etherscan.model.query;
 
-import io.api.etherscan.core.ILogsApi;
-import io.api.etherscan.error.LogQueryException;
-import io.api.etherscan.model.query.IQueryBuilder;
-import io.api.etherscan.model.query.LogOp;
+import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
+
+import io.goodforgod.api.etherscan.LogsAPI;
+import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Quadro topic parameter builder for The Event Log API
  *
- * @see LogQueryBuilder
- * @see ILogsApi
+ * @see LogQueryBuilderImpl
+ * @see LogsAPI
  * @author GoodforGod
  * @since 31.10.2018
  */
-public class LogTopicQuadro extends BaseLogQuery implements IQueryBuilder {
+public final class LogTopicQuadro implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
@@ -68,21 +69,21 @@ public LogTopicQuadro setOpTopic1_3(LogOp topic1_3_opr) {
     }
 
     @Override
-    public LogQuery build() {
+    public @NotNull LogQuery build() {
         if (topic0_1_opr == null)
-            throw new LogQueryException("topic0_1_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic0_1_opr can not be null.");
         if (topic0_2_opr == null)
-            throw new LogQueryException("topic0_2_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic0_2_opr can not be null.");
         if (topic0_3_opr == null)
-            throw new LogQueryException("topic0_3_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic0_3_opr can not be null.");
         if (topic1_2_opr == null)
-            throw new LogQueryException("topic1_2_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic1_2_opr can not be null.");
         if (topic2_3_opr == null)
-            throw new LogQueryException("topic2_3_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic2_3_opr can not be null.");
         if (topic1_3_opr == null)
-            throw new LogQueryException("topic1_3_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic1_3_opr can not be null.");
 
-        return new LogQuery(ADDRESS_PARAM + address
+        return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
                 + TOPIC_0_PARAM + topic0
                 + TOPIC_1_PARAM + topic1
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicSingle.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
similarity index 53%
rename from src/main/java/io/api/etherscan/model/query/impl/LogTopicSingle.java
rename to src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
index 83199d9..85bd18c 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicSingle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
@@ -1,18 +1,20 @@
-package io.api.etherscan.model.query.impl;
+package io.goodforgod.api.etherscan.model.query;
 
-import io.api.etherscan.core.ILogsApi;
-import io.api.etherscan.error.LogQueryException;
-import io.api.etherscan.model.query.IQueryBuilder;
+import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
+
+import io.goodforgod.api.etherscan.LogsAPI;
+import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Single topic parameter builder for The Event Log API
  *
- * @see LogQueryBuilder
- * @see ILogsApi
+ * @see LogQueryBuilderImpl
+ * @see LogsAPI
  * @author GoodforGod
  * @since 31.10.2018
  */
-public class LogTopicSingle extends BaseLogQuery implements IQueryBuilder {
+public final class LogTopicSingle implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
@@ -27,8 +29,8 @@ public class LogTopicSingle extends BaseLogQuery implements IQueryBuilder {
     }
 
     @Override
-    public LogQuery build() throws LogQueryException {
-        return new LogQuery(ADDRESS_PARAM + address
+    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
+        return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
                 + TOPIC_0_PARAM + topic0);
     }
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTriple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
similarity index 68%
rename from src/main/java/io/api/etherscan/model/query/impl/LogTopicTriple.java
rename to src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
index cc9a6ba..d56edb5 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTriple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
@@ -1,19 +1,20 @@
-package io.api.etherscan.model.query.impl;
+package io.goodforgod.api.etherscan.model.query;
 
-import io.api.etherscan.core.ILogsApi;
-import io.api.etherscan.error.LogQueryException;
-import io.api.etherscan.model.query.IQueryBuilder;
-import io.api.etherscan.model.query.LogOp;
+import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
+
+import io.goodforgod.api.etherscan.LogsAPI;
+import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Triple topic parameter builder for The Event Log API
  *
- * @see LogQueryBuilder
- * @see ILogsApi
+ * @see LogQueryBuilderImpl
+ * @see LogsAPI
  * @author GoodforGod
  * @since 31.10.2018
  */
-public class LogTopicTriple extends BaseLogQuery implements IQueryBuilder {
+public final class LogTopicTriple implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
@@ -51,15 +52,15 @@ public LogTopicTriple setOpTopic1_2(LogOp topic1_2_opr) {
     }
 
     @Override
-    public LogQuery build() throws LogQueryException {
+    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
         if (topic0_1_opr == null)
-            throw new LogQueryException("topic0_1_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic0_1_opr can not be null.");
         if (topic0_2_opr == null)
-            throw new LogQueryException("topic0_2_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic0_2_opr can not be null.");
         if (topic1_2_opr == null)
-            throw new LogQueryException("topic1_2_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic1_2_opr can not be null.");
 
-        return new LogQuery(ADDRESS_PARAM + address
+        return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
                 + TOPIC_0_PARAM + topic0
                 + TOPIC_1_PARAM + topic1
diff --git a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTuple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
similarity index 63%
rename from src/main/java/io/api/etherscan/model/query/impl/LogTopicTuple.java
rename to src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
index 4524a8a..95a78a4 100644
--- a/src/main/java/io/api/etherscan/model/query/impl/LogTopicTuple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
@@ -1,19 +1,20 @@
-package io.api.etherscan.model.query.impl;
+package io.goodforgod.api.etherscan.model.query;
 
-import io.api.etherscan.core.ILogsApi;
-import io.api.etherscan.error.LogQueryException;
-import io.api.etherscan.model.query.IQueryBuilder;
-import io.api.etherscan.model.query.LogOp;
+import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
+
+import io.goodforgod.api.etherscan.LogsAPI;
+import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Tuple topic parameter builder for The Event Log API
  *
- * @see LogQueryBuilder
- * @see ILogsApi
+ * @see LogQueryBuilderImpl
+ * @see LogsAPI
  * @author GoodforGod
  * @since 31.10.2018
  */
-public class LogTopicTuple extends BaseLogQuery implements IQueryBuilder {
+public final class LogTopicTuple implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
@@ -39,11 +40,11 @@ public LogTopicTuple setOpTopic0_1(LogOp topic0_1_opr) {
     }
 
     @Override
-    public LogQuery build() throws LogQueryException {
+    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
         if (topic0_1_opr == null)
-            throw new LogQueryException("topic0_1_opr can not be null.");
+            throw new ErtherScanLogQueryException("topic0_1_opr can not be null.");
 
-        return new LogQuery(ADDRESS_PARAM + address
+        return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
                 + TOPIC_0_PARAM + topic0
                 + TOPIC_1_PARAM + topic1
diff --git a/src/main/java/io/api/etherscan/model/utility/BalanceResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/BalanceResponseTO.java
similarity index 70%
rename from src/main/java/io/api/etherscan/model/utility/BalanceResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/BalanceResponseTO.java
index f7c2985..189ed87 100644
--- a/src/main/java/io/api/etherscan/model/utility/BalanceResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/BalanceResponseTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/BalanceTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/BalanceTO.java
similarity index 83%
rename from src/main/java/io/api/etherscan/model/utility/BalanceTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/BalanceTO.java
index 3956cec..8f56790 100644
--- a/src/main/java/io/api/etherscan/model/utility/BalanceTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/BalanceTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/BaseListResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/BaseListResponseTO.java
similarity index 82%
rename from src/main/java/io/api/etherscan/model/utility/BaseListResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/BaseListResponseTO.java
index 916739e..0d1b06c 100644
--- a/src/main/java/io/api/etherscan/model/utility/BaseListResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/BaseListResponseTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
 import java.util.List;
 
diff --git a/src/main/java/io/api/etherscan/model/utility/BaseResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/BaseResponseTO.java
similarity index 77%
rename from src/main/java/io/api/etherscan/model/utility/BaseResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/BaseResponseTO.java
index 9679ebb..3e100d1 100644
--- a/src/main/java/io/api/etherscan/model/utility/BaseResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/BaseResponseTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/BlockParam.java b/src/main/java/io/goodforgod/api/etherscan/model/response/BlockParam.java
similarity index 88%
rename from src/main/java/io/api/etherscan/model/utility/BlockParam.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/BlockParam.java
index 7e11a00..b2dbd32 100644
--- a/src/main/java/io/api/etherscan/model/utility/BlockParam.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/BlockParam.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/BlockResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/BlockResponseTO.java
similarity index 54%
rename from src/main/java/io/api/etherscan/model/utility/BlockResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/BlockResponseTO.java
index 8a89321..363612b 100644
--- a/src/main/java/io/api/etherscan/model/utility/BlockResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/BlockResponseTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.model.Block;
+import io.goodforgod.api.etherscan.model.Block;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/LogResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/LogResponseTO.java
similarity index 54%
rename from src/main/java/io/api/etherscan/model/utility/LogResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/LogResponseTO.java
index a060bd3..748d155 100644
--- a/src/main/java/io/api/etherscan/model/utility/LogResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/LogResponseTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.model.Log;
+import io.goodforgod.api.etherscan.model.Log;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/PriceResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/PriceResponseTO.java
similarity index 66%
rename from src/main/java/io/api/etherscan/model/utility/PriceResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/PriceResponseTO.java
index 9af743b..e2f0b63 100644
--- a/src/main/java/io/api/etherscan/model/utility/PriceResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/PriceResponseTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.model.Price;
+import io.goodforgod.api.etherscan.model.Price;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/ReceiptStatusResponseTO.java
similarity index 81%
rename from src/main/java/io/api/etherscan/model/utility/ReceiptStatusResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/ReceiptStatusResponseTO.java
index a5f9577..922c5e2 100644
--- a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/ReceiptStatusResponseTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/ReceiptStatusTO.java
similarity index 77%
rename from src/main/java/io/api/etherscan/model/utility/ReceiptStatusTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/ReceiptStatusTO.java
index c4c63af..4f4717c 100644
--- a/src/main/java/io/api/etherscan/model/utility/ReceiptStatusTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/ReceiptStatusTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/StatusResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/StatusResponseTO.java
similarity index 66%
rename from src/main/java/io/api/etherscan/model/utility/StatusResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/StatusResponseTO.java
index 7532aba..6847930 100644
--- a/src/main/java/io/api/etherscan/model/utility/StatusResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/StatusResponseTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.model.Status;
+import io.goodforgod.api.etherscan.model.Status;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/StringResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
similarity index 79%
rename from src/main/java/io/api/etherscan/model/utility/StringResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
index 582087a..4fb9f04 100644
--- a/src/main/java/io/api/etherscan/model/utility/StringResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
@@ -1,4 +1,4 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java
new file mode 100644
index 0000000..f4814a5
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxERC20;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class TxERC20ResponseTO extends BaseListResponseTO<TxERC20> {
+
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java
new file mode 100644
index 0000000..b4db8ef
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxERC20;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class TxERC721ResponseTO extends BaseListResponseTO<TxERC20> {
+
+}
diff --git a/src/main/java/io/api/etherscan/model/utility/TxInternalResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxInternalResponseTO.java
similarity index 55%
rename from src/main/java/io/api/etherscan/model/utility/TxInternalResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/TxInternalResponseTO.java
index 5f0e400..efcf4dd 100644
--- a/src/main/java/io/api/etherscan/model/utility/TxInternalResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxInternalResponseTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.model.TxInternal;
+import io.goodforgod.api.etherscan.model.TxInternal;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/api/etherscan/model/utility/TxResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxResponseTO.java
similarity index 54%
rename from src/main/java/io/api/etherscan/model/utility/TxResponseTO.java
rename to src/main/java/io/goodforgod/api/etherscan/model/response/TxResponseTO.java
index 1fa6b16..f4bd3f0 100644
--- a/src/main/java/io/api/etherscan/model/utility/TxResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxResponseTO.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.model.Tx;
+import io.goodforgod.api.etherscan.model.Tx;
 
 /**
  * @author GoodforGod
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/UncleBlockResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/UncleBlockResponseTO.java
new file mode 100644
index 0000000..de94f9e
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/UncleBlockResponseTO.java
@@ -0,0 +1,16 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.BlockUncle;
+
+/**
+ * @author GoodforGod
+ * @since 30.10.2018
+ */
+public class UncleBlockResponseTO extends BaseResponseTO {
+
+    private BlockUncle result;
+
+    public BlockUncle getResult() {
+        return result;
+    }
+}
diff --git a/src/main/java/io/api/etherscan/util/BasicUtils.java b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
similarity index 80%
rename from src/main/java/io/api/etherscan/util/BasicUtils.java
rename to src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
index d748abf..4522ff5 100644
--- a/src/main/java/io/api/etherscan/util/BasicUtils.java
+++ b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
@@ -1,10 +1,10 @@
-package io.api.etherscan.util;
+package io.goodforgod.api.etherscan.util;
 
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.error.InvalidTxHashException;
-import io.api.etherscan.model.utility.BaseResponseTO;
-import io.api.etherscan.model.utility.BlockParam;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidTxHashException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.model.response.BaseResponseTO;
+import io.goodforgod.api.etherscan.model.response.BlockParam;
 import java.math.BigInteger;
 import java.util.*;
 import java.util.regex.Pattern;
@@ -16,7 +16,9 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class BasicUtils {
+public final class BasicUtils {
+
+    private BasicUtils() {}
 
     private static final int MAX_END_BLOCK = 999999999;
     private static final int MIN_START_BLOCK = 0;
@@ -25,8 +27,6 @@ public class BasicUtils {
     private static final Pattern TXHASH_PATTERN = Pattern.compile("0x[a-zA-Z0-9]{64}");
     private static final Pattern HEX_PATTERN = Pattern.compile("[a-zA-Z0-9]+");
 
-    private BasicUtils() {}
-
     public static boolean isEmpty(String value) {
         return value == null || value.isEmpty();
     }
@@ -78,7 +78,7 @@ public static BigInteger parseHex(String hex) {
                 return BigInteger.valueOf(0);
 
             final String formatted = (hex.length() > 2 && hex.charAt(0) == '0' && hex.charAt(1) == 'x')
-                    ? hex.substring(2, hex.length())
+                    ? hex.substring(2)
                     : hex;
 
             return new BigInteger(formatted, 16);
@@ -89,24 +89,24 @@ public static BigInteger parseHex(String hex) {
 
     public static void validateAddress(String address) {
         if (isNotAddress(address))
-            throw new InvalidAddressException("Address [" + address + "] is not Ethereum based.");
+            throw new EtherScanInvalidAddressException("Address [" + address + "] is not Ethereum based.");
     }
 
     public static void validateTxHash(String txhash) {
         if (isNotTxHash(txhash))
-            throw new InvalidTxHashException("TxHash [" + txhash + "] is not Ethereum based.");
+            throw new EtherScanInvalidTxHashException("TxHash [" + txhash + "] is not Ethereum based.");
     }
 
     public static <T extends BaseResponseTO> void validateTxResponse(T response) {
         if (response == null)
-            throw new EtherScanException("EtherScan responded with null value");
+            throw new EtherScanResponseException("EtherScan responded with null value");
 
         if (response.getStatus() != 1) {
             if (response.getMessage() == null) {
-                throw new EtherScanException(
+                throw new EtherScanResponseException(
                         "Unexpected Etherscan exception, no information from server about error, code " + response.getStatus());
             } else if (!response.getMessage().startsWith("No tra") && !response.getMessage().startsWith("No rec")) {
-                throw new EtherScanException(response);
+                throw new EtherScanResponseException(response);
             }
         }
     }
@@ -114,7 +114,7 @@ public static <T extends BaseResponseTO> void validateTxResponse(T response) {
     public static void validateAddresses(List<String> addresses) {
         for (String address : addresses) {
             if (isNotAddress(address))
-                throw new InvalidAddressException("Address [" + address + "] is not Ethereum based.");
+                throw new EtherScanInvalidAddressException("Address [" + address + "] is not Ethereum based.");
         }
     }
 
diff --git a/src/test/java/io/api/ApiRunner.java b/src/test/java/io/api/ApiRunner.java
deleted file mode 100644
index e78ea6d..0000000
--- a/src/test/java/io/api/ApiRunner.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package io.api;
-
-import io.api.etherscan.core.impl.EtherScanApi;
-import io.api.etherscan.manager.impl.QueueManager;
-import io.api.etherscan.model.EthNetwork;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.Assertions;
-
-public class ApiRunner extends Assertions {
-
-    private static final EtherScanApi api;
-    private static final EtherScanApi apiRopsten;
-    private static final EtherScanApi apiRinkeby;
-    private static final EtherScanApi apiKovan;
-    private static final String apiKey;
-
-    static {
-        final String key = System.getenv("API_KEY");
-        apiKey = (key == null || key.isEmpty())
-                ? EtherScanApi.DEFAULT_KEY
-                : key;
-
-        final QueueManager queueManager = (EtherScanApi.DEFAULT_KEY.equals(apiKey))
-                ? QueueManager.DEFAULT_KEY_QUEUE
-                : new QueueManager(1, 1200L, 1200L, 0);
-
-        api = new EtherScanApi(ApiRunner.apiKey, EthNetwork.MAINNET, queueManager);
-        apiKovan = new EtherScanApi(ApiRunner.apiKey, EthNetwork.KOVAN, queueManager);
-        apiRopsten = new EtherScanApi(ApiRunner.apiKey, EthNetwork.ROPSTEN, queueManager);
-        apiRinkeby = new EtherScanApi(ApiRunner.apiKey, EthNetwork.RINKEBY, queueManager);
-    }
-
-    public static String getApiKey() {
-        return apiKey;
-    }
-
-    public static EtherScanApi getApi() {
-        return api;
-    }
-
-    public static EtherScanApi getApiRopsten() {
-        return apiRopsten;
-    }
-
-    public static EtherScanApi getApiRinkeby() {
-        return apiRinkeby;
-    }
-
-    public static EtherScanApi getApiKovan() {
-        return apiKovan;
-    }
-
-    @AfterAll
-    public static void cleanup() throws Exception {
-        api.close();
-        apiRopsten.close();
-        apiRinkeby.close();
-        apiKovan.close();
-    }
-}
diff --git a/src/test/java/io/api/etherscan/EtherScanApiTest.java b/src/test/java/io/api/etherscan/EtherScanApiTest.java
deleted file mode 100644
index b649302..0000000
--- a/src/test/java/io/api/etherscan/EtherScanApiTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package io.api.etherscan;
-
-import io.api.ApiRunner;
-import io.api.etherscan.core.impl.EtherScanApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.ApiKeyException;
-import io.api.etherscan.error.ApiTimeoutException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.executor.impl.HttpExecutor;
-import io.api.etherscan.model.Balance;
-import io.api.etherscan.model.EthNetwork;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-import org.junit.jupiter.api.Test;
-
-/**
- * @author GoodforGod
- * @since 05.11.2018
- */
-class EtherScanApiTest extends ApiRunner {
-
-    private final EthNetwork network = EthNetwork.KOVAN;
-    private final String validKey = "YourKey";
-
-    @Test
-    void validKey() {
-        EtherScanApi api = new EtherScanApi(validKey, network);
-        assertNotNull(api);
-    }
-
-    @Test
-    void emptyKey() {
-        assertThrows(ApiKeyException.class, () -> new EtherScanApi(""));
-    }
-
-    @Test
-    void blankKey() {
-        assertThrows(ApiKeyException.class, () -> new EtherScanApi("         ", network));
-    }
-
-    @Test
-    void nullNetwork() {
-        assertThrows(ApiException.class, () -> new EtherScanApi(validKey, null));
-    }
-
-    @Test
-    void noTimeoutOnRead() {
-        Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(300);
-        EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET, supplier);
-        Balance balance = api.account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
-    @Test
-    void noTimeoutOnReadGroli() {
-        Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(300);
-        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
-    @Test
-    void noTimeoutOnReadTobalala() {
-        Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(30000);
-        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
-    @Test
-    void noTimeoutUnlimitedAwait() {
-        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
-    @Test
-    void timeout() throws InterruptedException {
-        TimeUnit.SECONDS.sleep(5);
-        Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(300, 300);
-        EtherScanApi api = new EtherScanApi(getApiKey(), EthNetwork.KOVAN, supplier);
-        assertThrows(ApiTimeoutException.class, () -> api.account().minedBlocks("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D"));
-    }
-}
diff --git a/src/test/java/io/api/manager/QueueManagerTest.java b/src/test/java/io/api/manager/QueueManagerTest.java
deleted file mode 100644
index 7bd53a9..0000000
--- a/src/test/java/io/api/manager/QueueManagerTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package io.api.manager;
-
-import io.api.ApiRunner;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.manager.impl.FakeQueueManager;
-import io.api.etherscan.manager.impl.QueueManager;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.Timeout;
-
-/**
- * @author GoodforGod
- * @since 03.11.2018
- */
-class QueueManagerTest extends ApiRunner {
-
-    @Test
-    void fakeManager() {
-        IQueueManager fakeManager = new FakeQueueManager();
-        fakeManager.takeTurn();
-        fakeManager.takeTurn();
-        fakeManager.takeTurn();
-        fakeManager.takeTurn();
-        fakeManager.takeTurn();
-        fakeManager.takeTurn();
-        assertNotNull(fakeManager);
-    }
-
-    @Test
-    @Timeout(3500)
-    void queueManager() {
-        IQueueManager queueManager = new QueueManager(1, 3);
-        queueManager.takeTurn();
-        queueManager.takeTurn();
-        assertNotNull(queueManager);
-    }
-
-    @Test
-    @Timeout(4500)
-    void queueManagerWithDelay() {
-        IQueueManager queueManager = new QueueManager(1, 2, 2);
-        queueManager.takeTurn();
-        queueManager.takeTurn();
-        assertNotNull(queueManager);
-    }
-
-    @Test
-    void queueManagerTimeout() {
-        IQueueManager queueManager = new QueueManager(1, 3);
-        queueManager.takeTurn();
-        long start = System.currentTimeMillis();
-        queueManager.takeTurn();
-        long end = System.currentTimeMillis();
-        assertEquals(3, Math.round((double) (end - start) / 1000));
-    }
-}
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
new file mode 100644
index 0000000..3b9cbe2
--- /dev/null
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -0,0 +1,66 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.manager.impl.SemaphoreRequestQueueManager;
+import java.time.Duration;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+
+public class ApiRunner extends Assertions {
+
+    private static final String DEFAULT_KEY = "YourApiKeyToken";
+
+    private static final EtherScanAPI api;
+    private static final EtherScanAPI apiRopsten;
+    private static final EtherScanAPI apiRinkeby;
+    private static final EtherScanAPI apiKovan;
+    private static final String apiKey;
+
+    static {
+        final String key = System.getenv("API_KEY");
+        apiKey = (key == null || key.isEmpty())
+                ? DEFAULT_KEY
+                : key;
+
+        final RequestQueueManager queueManager = (DEFAULT_KEY.equals(apiKey))
+                ? RequestQueueManager.DEFAULT_KEY_QUEUE
+                : new SemaphoreRequestQueueManager(1, Duration.ofMillis(1200L), Duration.ofMillis(1200L), 0);
+
+        api = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
+                .build();
+        apiKovan = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.KOVAN).withQueue(queueManager)
+                .build();
+        apiRopsten = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.ROPSTEN).withQueue(queueManager)
+                .build();
+        apiRinkeby = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.RINKEBY).withQueue(queueManager)
+                .build();
+    }
+
+    public static String getApiKey() {
+        return apiKey;
+    }
+
+    public static EtherScanAPI getApi() {
+        return api;
+    }
+
+    public static EtherScanAPI getApiRopsten() {
+        return apiRopsten;
+    }
+
+    public static EtherScanAPI getApiRinkeby() {
+        return apiRinkeby;
+    }
+
+    public static EtherScanAPI getApiKovan() {
+        return apiKovan;
+    }
+
+    @AfterAll
+    public static void cleanup() throws Exception {
+        api.close();
+        apiRopsten.close();
+        apiRinkeby.close();
+        apiKovan.close();
+    }
+}
diff --git a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
new file mode 100644
index 0000000..5cc0fe7
--- /dev/null
+++ b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
@@ -0,0 +1,76 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanKeyException;
+import io.goodforgod.api.etherscan.error.EtherScanTimeoutException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.executor.impl.UrlEthHttpClient;
+import io.goodforgod.api.etherscan.model.Balance;
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author GoodforGod
+ * @since 05.11.2018
+ */
+class EtherScanAPITests extends ApiRunner {
+
+    private final EthNetworks network = EthNetworks.KOVAN;
+    private final String validKey = "YourKey";
+
+    @Test
+    void validKey() {
+        EtherScanAPI api = EtherScanAPI.builder().withApiKey(validKey).withNetwork(network).build();
+        assertNotNull(api);
+    }
+
+    @Test
+    void emptyKey() {
+        assertThrows(EtherScanKeyException.class, () -> EtherScanAPI.builder().withApiKey("").build());
+    }
+
+    @Test
+    void blankKey() {
+        assertThrows(EtherScanKeyException.class,
+                () -> EtherScanAPI.builder().withApiKey("         ").withNetwork(network).build());
+    }
+
+    @Test
+    void noTimeoutOnRead() {
+        Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300));
+        EtherScanAPI api = EtherScanAPI.builder().withNetwork(EthNetworks.MAINNET).withHttpClient(supplier).build();
+        Balance balance = api.account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
+        assertNotNull(balance);
+    }
+
+    @Test
+    void noTimeoutOnReadGroli() {
+        Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300));
+        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
+        assertNotNull(balance);
+    }
+
+    @Test
+    void noTimeoutOnReadTobalala() {
+        Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(30000));
+        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
+        assertNotNull(balance);
+    }
+
+    @Test
+    void noTimeoutUnlimitedAwait() {
+        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
+        assertNotNull(balance);
+    }
+
+    @Test
+    void timeout() throws InterruptedException {
+        TimeUnit.SECONDS.sleep(5);
+        Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300), Duration.ofMillis(300));
+        EtherScanAPI api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.KOVAN).withHttpClient(supplier)
+                .build();
+        assertThrows(EtherScanTimeoutException.class,
+                () -> api.account().blocksMined("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D"));
+    }
+}
diff --git a/src/test/java/io/api/etherscan/account/AccountBalanceListTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTest.java
similarity index 88%
rename from src/test/java/io/api/etherscan/account/AccountBalanceListTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTest.java
index 6864175..cd3dac9 100644
--- a/src/test/java/io/api/etherscan/account/AccountBalanceListTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTest.java
@@ -1,9 +1,9 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.Balance;
-import io.api.support.AddressUtil;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.Balance;
+import io.goodforgod.api.etherscan.support.AddressUtil;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
@@ -61,7 +61,7 @@ void invalidParamWithError() {
         addresses.add("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
         addresses.add("C9F32CE1127e44C51cbD182D6364F3D707Fd0d47");
 
-        assertThrows(InvalidAddressException.class, () -> getApi().account().balances(addresses));
+        assertThrows(EtherScanInvalidAddressException.class, () -> getApi().account().balances(addresses));
     }
 
     @Test
diff --git a/src/test/java/io/api/etherscan/account/AccountBalanceTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTest.java
similarity index 67%
rename from src/test/java/io/api/etherscan/account/AccountBalanceTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTest.java
index d5427ab..4c06c7c 100644
--- a/src/test/java/io/api/etherscan/account/AccountBalanceTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTest.java
@@ -1,9 +1,9 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.core.impl.EtherScanApi;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.Balance;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.EtherScanAPI;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.Balance;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -12,7 +12,7 @@
  */
 class AccountBalanceTest extends ApiRunner {
 
-    private final EtherScanApi api = getApi();
+    private final EtherScanAPI api = getApi();
 
     @Test
     void correct() {
@@ -29,7 +29,8 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class, () -> getApi().account().balance("8d4426f94e42f721C7116E81d6688cd935cB3b4F"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().account().balance("8d4426f94e42f721C7116E81d6688cd935cB3b4F"));
     }
 
     @Test
diff --git a/src/test/java/io/api/etherscan/account/AccountMinedBlocksTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTest.java
similarity index 65%
rename from src/test/java/io/api/etherscan/account/AccountMinedBlocksTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTest.java
index ae16174..13d5075 100644
--- a/src/test/java/io/api/etherscan/account/AccountMinedBlocksTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTest.java
@@ -1,9 +1,9 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.core.impl.EtherScanApi;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.Block;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.EtherScanAPI;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.Block;
 import java.util.List;
 import org.junit.jupiter.api.Test;
 
@@ -13,11 +13,11 @@
  */
 class AccountMinedBlocksTest extends ApiRunner {
 
-    private final EtherScanApi api = getApi();
+    private final EtherScanAPI api = getApi();
 
     @Test
     void correct() {
-        List<Block> blocks = api.account().minedBlocks("0xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23");
+        List<Block> blocks = api.account().blocksMined("0xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23");
         assertNotNull(blocks);
 
         assertEquals(223, blocks.size());
@@ -32,13 +32,13 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class,
-                () -> getApi().account().minedBlocks("xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().account().blocksMined("xE4C6175183029A0f039bf2DFffa5C6e8F3cA9B23"));
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        List<Block> txs = api.account().minedBlocks("0xE1C6175183029A0f039bf2DFffa5C6e8F3cA9B23");
+        List<Block> txs = api.account().blocksMined("0xE1C6175183029A0f039bf2DFffa5C6e8F3cA9B23");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
     }
diff --git a/src/test/java/io/api/etherscan/account/AccountTokenBalanceTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTest.java
similarity index 63%
rename from src/test/java/io/api/etherscan/account/AccountTokenBalanceTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTest.java
index b8b8146..4df75f3 100644
--- a/src/test/java/io/api/etherscan/account/AccountTokenBalanceTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTest.java
@@ -1,9 +1,9 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.core.impl.EtherScanApi;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.TokenBalance;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.EtherScanAPI;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.TokenBalance;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -12,7 +12,7 @@
  */
 class AccountTokenBalanceTest extends ApiRunner {
 
-    private final EtherScanApi api = getApi();
+    private final EtherScanAPI api = getApi();
 
     @Test
     void correct() {
@@ -31,14 +31,16 @@ void correct() {
 
     @Test
     void invalidAddressParamWithError() {
-        assertThrows(InvalidAddressException.class, () -> api.account().balance("0x5807e7F124EC2103a59c5249187f772c0b8D6b2",
-                "0x5EaC95ad5b287cF44E058dCf694419333b796123"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> api.account().balance("0x5807e7F124EC2103a59c5249187f772c0b8D6b2",
+                        "0x5EaC95ad5b287cF44E058dCf694419333b796123"));
     }
 
     @Test
     void invalidContractParamWithError() {
-        assertThrows(InvalidAddressException.class, () -> api.account().balance("0x5d807e7F124EC2103a59c5249187f772c0b8D6b2",
-                "0xEaC95ad5b287cF44E058dCf694419333b796123"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> api.account().balance("0x5d807e7F124EC2103a59c5249187f772c0b8D6b2",
+                        "0xEaC95ad5b287cF44E058dCf694419333b796123"));
     }
 
     @Test
diff --git a/src/test/java/io/api/etherscan/account/AccountTxTokenTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxERC20Test.java
similarity index 72%
rename from src/test/java/io/api/etherscan/account/AccountTxTokenTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxERC20Test.java
index 044991b..bacf2e3 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxTokenTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxERC20Test.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.TxToken;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.TxERC20;
 import java.util.List;
 import org.junit.jupiter.api.Test;
 
@@ -10,11 +10,11 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountTxTokenTest extends ApiRunner {
+class AccountTxERC20Test extends ApiRunner {
 
     @Test
     void correct() {
-        List<TxToken> txs = getApi().account().txsToken("0xE376F69ED2218076682e2b3B7b9099eC50aD68c4");
+        List<TxERC20> txs = getApi().account().txsERC20("0xE376F69ED2218076682e2b3B7b9099eC50aD68c4");
         assertNotNull(txs);
         assertEquals(3, txs.size());
         assertTxs(txs);
@@ -33,7 +33,7 @@ void correct() {
 
     @Test
     void correctStartBlock() {
-        List<TxToken> txs = getApi().account().txsToken("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167);
+        List<TxERC20> txs = getApi().account().txsERC20("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167);
         assertNotNull(txs);
         assertEquals(11, txs.size());
         assertTxs(txs);
@@ -41,7 +41,7 @@ void correctStartBlock() {
 
     @Test
     void correctStartBlockEndBlock() {
-        List<TxToken> txs = getApi().account().txsToken("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167, 5813576);
+        List<TxERC20> txs = getApi().account().txsERC20("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167, 5813576);
         assertNotNull(txs);
         assertEquals(5, txs.size());
         assertTxs(txs);
@@ -49,19 +49,19 @@ void correctStartBlockEndBlock() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class,
-                () -> getApi().account().txsToken("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().account().txsERC20("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        List<TxToken> txs = getApi().account().txsToken("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
+        List<TxERC20> txs = getApi().account().txsERC20("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
     }
 
-    private void assertTxs(List<TxToken> txs) {
-        for (TxToken tx : txs) {
+    private void assertTxs(List<TxERC20> txs) {
+        for (TxERC20 tx : txs) {
             assertNotNull(tx.getBlockHash());
             assertNotNull(tx.getTokenName());
             assertNotNull(tx.getTokenSymbol());
diff --git a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTest.java
similarity index 81%
rename from src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTest.java
index 4e63dbc..13036bc 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxInternalByHashTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTest.java
@@ -1,10 +1,10 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.core.impl.EtherScanApi;
-import io.api.etherscan.error.InvalidTxHashException;
-import io.api.etherscan.model.TxInternal;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.EtherScanAPI;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidTxHashException;
+import io.goodforgod.api.etherscan.model.TxInternal;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.util.List;
 import org.junit.jupiter.api.Test;
 
@@ -14,7 +14,7 @@
  */
 class AccountTxInternalByHashTest extends ApiRunner {
 
-    private final EtherScanApi api = getApi();
+    private final EtherScanAPI api = getApi();
 
     @Test
     void correct() {
@@ -42,7 +42,7 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidTxHashException.class,
+        assertThrows(EtherScanInvalidTxHashException.class,
                 () -> api.account().txsInternalByHash("0xb513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b"));
     }
 
diff --git a/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTest.java
similarity index 86%
rename from src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTest.java
index 7144671..6fb92b4 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxInternalTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.TxInternal;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.TxInternal;
 import java.util.List;
 import org.junit.jupiter.api.Test;
 
@@ -41,7 +41,7 @@ void correctStartBlockEndBlock() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class,
+        assertThrows(EtherScanInvalidAddressException.class,
                 () -> getApi().account().txsInternal("0x2C1ba59D6F58433FB1EaEe7d20b26Ed83bDA51"));
     }
 
diff --git a/src/test/java/io/api/etherscan/account/AccountTxRc721TokenTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
similarity index 65%
rename from src/test/java/io/api/etherscan/account/AccountTxRc721TokenTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
index 6601d1a..c85aaa4 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxRc721TokenTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
@@ -1,9 +1,11 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.TxToken;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.TxERC20;
 import java.util.List;
+
+import io.goodforgod.api.etherscan.model.TxERC721;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -14,7 +16,7 @@ class AccountTxRc721TokenTest extends ApiRunner {
 
     @Test
     void correct() {
-        List<TxToken> txs = getApi().account().txsNftToken("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67");
+        List<TxERC721> txs = getApi().account().txsERC721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67");
         assertNotNull(txs);
         assertEquals(16, txs.size());
         assertTxs(txs);
@@ -33,7 +35,7 @@ void correct() {
 
     @Test
     void correctStartBlock() {
-        List<TxToken> txs = getApi().account().txsNftToken("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4762071);
+        List<TxERC721> txs = getApi().account().txsERC721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4762071);
         System.out.println(txs);
         assertNotNull(txs);
         assertEquals(5, txs.size());
@@ -42,7 +44,7 @@ void correctStartBlock() {
 
     @Test
     void correctStartBlockEndBlock() {
-        List<TxToken> txs = getApi().account().txsNftToken("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4761862, 4761934);
+        List<TxERC721> txs = getApi().account().txsERC721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4761862, 4761934);
         System.out.println(txs);
         assertNotNull(txs);
         assertEquals(11, txs.size());
@@ -51,19 +53,19 @@ void correctStartBlockEndBlock() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class,
-                () -> getApi().account().txsNftToken("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().account().txsERC721("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        List<TxToken> txs = getApi().account().txsNftToken("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
+        List<TxERC721> txs = getApi().account().txsERC721("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
     }
 
-    private void assertTxs(List<TxToken> txs) {
-        for (TxToken tx : txs) {
+    private void assertTxs(List<TxERC721> txs) {
+        for (TxERC721 tx : txs) {
             assertNotNull(tx.getBlockHash());
             assertNotNull(tx.getTokenName());
             assertNotNull(tx.getTokenSymbol());
diff --git a/src/test/java/io/api/etherscan/account/AccountTxsTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTest.java
similarity index 87%
rename from src/test/java/io/api/etherscan/account/AccountTxsTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTest.java
index 899d0fb..a2cffd1 100644
--- a/src/test/java/io/api/etherscan/account/AccountTxsTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.account;
+package io.goodforgod.api.etherscan.account;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.Tx;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.Tx;
 import java.util.List;
 import org.junit.jupiter.api.Test;
 
@@ -54,7 +54,8 @@ void correctStartBlockEndBlock() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class, () -> getApi().account().txs("9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().account().txs("9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9"));
     }
 
     @Test
diff --git a/src/test/java/io/api/etherscan/block/BlockApiTest.java b/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTest.java
similarity index 82%
rename from src/test/java/io/api/etherscan/block/BlockApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/block/BlockApiTest.java
index cee8bb9..8e3b529 100644
--- a/src/test/java/io/api/etherscan/block/BlockApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.block;
+package io.goodforgod.api.etherscan.block;
 
-import io.api.ApiRunner;
-import io.api.etherscan.model.UncleBlock;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.model.BlockUncle;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -13,7 +13,7 @@ class BlockApiTest extends ApiRunner {
 
     @Test
     void correct() {
-        Optional<UncleBlock> uncle = getApi().block().uncles(2165403);
+        Optional<BlockUncle> uncle = getApi().block().uncles(2165403);
         assertTrue(uncle.isPresent());
         assertFalse(uncle.get().isEmpty());
         assertNotNull(uncle.get().getBlockMiner());
@@ -25,7 +25,7 @@ void correct() {
         assertNotEquals(-1, uncle.get().getUncles().get(0).getUnclePosition());
         assertNotNull(uncle.get().toString());
 
-        UncleBlock empty = new UncleBlock();
+        BlockUncle empty = new BlockUncle();
         assertNotEquals(uncle.get().hashCode(), empty.hashCode());
         assertNotEquals(uncle.get(), empty);
         assertTrue(empty.isEmpty());
@@ -44,14 +44,14 @@ void correct() {
 
     @Test
     void correctNoUncles() {
-        Optional<UncleBlock> uncles = getApi().block().uncles(34);
+        Optional<BlockUncle> uncles = getApi().block().uncles(34);
         assertTrue(uncles.isPresent());
         assertTrue(uncles.get().getUncles().isEmpty());
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        Optional<UncleBlock> uncles = getApi().block().uncles(99999999934L);
+        Optional<BlockUncle> uncles = getApi().block().uncles(99999999934L);
         assertFalse(uncles.isPresent());
     }
 }
diff --git a/src/test/java/io/api/etherscan/contract/ContractApiTest.java b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTest.java
similarity index 78%
rename from src/test/java/io/api/etherscan/contract/ContractApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTest.java
index 85fb905..62aa7da 100644
--- a/src/test/java/io/api/etherscan/contract/ContractApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.contract;
+package io.goodforgod.api.etherscan.contract;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.model.Abi;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.Abi;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -27,7 +27,7 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class,
+        assertThrows(EtherScanInvalidAddressException.class,
                 () -> getApi().contract().contractAbi("0xBBbc244D798123fDe783fCc1C72d3Bb8C189413"));
     }
 
diff --git a/src/test/java/io/api/etherscan/logs/LogQueryBuilderTest.java b/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTest.java
similarity index 59%
rename from src/test/java/io/api/etherscan/logs/LogQueryBuilderTest.java
rename to src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTest.java
index f956364..752c34c 100644
--- a/src/test/java/io/api/etherscan/logs/LogQueryBuilderTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTest.java
@@ -1,12 +1,9 @@
-package io.api.etherscan.logs;
-
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.error.LogQueryException;
-import io.api.etherscan.model.query.LogOp;
-import io.api.etherscan.model.query.impl.LogQuery;
-import io.api.etherscan.model.query.impl.LogQueryBuilder;
-import io.api.etherscan.model.query.impl.LogTopicQuadro;
+package io.goodforgod.api.etherscan.logs;
+
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.query.*;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -17,53 +14,55 @@ class LogQueryBuilderTest extends ApiRunner {
 
     @Test
     void singleCorrect() {
-        LogQuery single = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
+        LogQuery single = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .build();
 
         assertNotNull(single);
-        assertNotNull(single.getParams());
+        assertNotNull(single.params());
     }
 
     @Test
     void singleInCorrectAddress() {
-        assertThrows(InvalidAddressException.class, () -> LogQueryBuilder.with("033990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
-                .build());
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> LogQuery.builder("033990122638b9132ca29c723bdf037f1a891a70c")
+                        .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
+                        .build());
     }
 
     @Test
     void singleInCorrectTopic() {
-        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("6516=")
+        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("6516=")
                 .build());
     }
 
     @Test
     void tupleCorrect() {
-        LogQuery tuple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224)
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        LogQuery tuple = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224)
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                 .setOpTopic0_1(LogOp.AND)
                 .build();
 
         assertNotNull(tuple);
-        assertNotNull(tuple.getParams());
+        assertNotNull(tuple.params());
     }
 
     @Test
     void tupleInCorrectOp() {
-        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224)
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
-                        "0x72657075746174696f6e00000000000000000000000000000000000000000000")
-                .setOpTopic0_1(null)
-                .build());
+        assertThrows(ErtherScanLogQueryException.class,
+                () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224)
+                        .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+                                "0x72657075746174696f6e00000000000000000000000000000000000000000000")
+                        .setOpTopic0_1(null)
+                        .build());
     }
 
     @Test
     void tripleCorrect() {
-        LogQuery triple = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        LogQuery triple = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                 .setOpTopic0_1(LogOp.AND)
@@ -72,14 +71,14 @@ void tripleCorrect() {
                 .build();
 
         assertNotNull(triple);
-        assertNotNull(triple.getParams());
+        assertNotNull(triple.params());
     }
 
     @Test
     void tripleInCorrectOp() {
-        assertThrows(LogQueryException.class,
-                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                        .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        assertThrows(ErtherScanLogQueryException.class,
+                () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
+                        .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                         .setOpTopic0_1(LogOp.AND)
@@ -90,9 +89,9 @@ void tripleInCorrectOp() {
 
     @Test
     void tripleInCorrectTopic1() {
-        assertThrows(LogQueryException.class,
-                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                        .topic(null,
+        assertThrows(ErtherScanLogQueryException.class,
+                () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
+                        .withTopic(null,
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                         .setOpTopic0_1(LogOp.AND)
@@ -103,9 +102,9 @@ void tripleInCorrectTopic1() {
 
     @Test
     void tripleInCorrectTopic2() {
-        assertThrows(LogQueryException.class,
-                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                        .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        assertThrows(ErtherScanLogQueryException.class,
+                () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
+                        .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                                 null,
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                         .setOpTopic0_1(LogOp.AND)
@@ -116,9 +115,9 @@ void tripleInCorrectTopic2() {
 
     @Test
     void tripleInCorrectTopic3() {
-        assertThrows(LogQueryException.class,
-                () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-                        .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        assertThrows(ErtherScanLogQueryException.class,
+                () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
+                        .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                                 null)
                         .setOpTopic0_1(LogOp.AND)
@@ -129,8 +128,8 @@ void tripleInCorrectTopic3() {
 
     @Test
     void quadroCorrect() {
-        LogQuery quadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        LogQuery quadro = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
@@ -143,13 +142,13 @@ void quadroCorrect() {
                 .build();
 
         assertNotNull(quadro);
-        assertNotNull(quadro.getParams());
+        assertNotNull(quadro.params());
     }
 
     @Test
     void quadroIncorrectTopic2() {
-        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         null,
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
@@ -164,8 +163,8 @@ void quadroIncorrectTopic2() {
 
     @Test
     void tupleIncorrectTopic2() {
-        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         null)
                 .setOpTopic0_1(LogOp.AND)
                 .build());
@@ -173,8 +172,8 @@ void tupleIncorrectTopic2() {
 
     @Test
     void tupleIncorrectTopic1() {
-        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic(null,
+        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic(null,
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .setOpTopic0_1(LogOp.AND)
                 .build());
@@ -182,13 +181,13 @@ void tupleIncorrectTopic1() {
 
     @Test
     void quadroIncorrectOp1() {
-        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        final LogTopicQuadro topicQuadro = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        assertThrows(LogQueryException.class, () -> topicQuadro
+        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(null)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -200,13 +199,13 @@ void quadroIncorrectOp1() {
 
     @Test
     void quadroIncorrectOp2() {
-        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        final LogTopicQuadro topicQuadro = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        assertThrows(LogQueryException.class, () -> topicQuadro.setOpTopic0_1(LogOp.AND)
+        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro.setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(null)
                 .setOpTopic0_3(LogOp.AND)
                 .setOpTopic1_2(LogOp.OR)
@@ -217,13 +216,13 @@ void quadroIncorrectOp2() {
 
     @Test
     void quadroIncorrectOp3() {
-        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        final LogTopicQuadro topicQuadro = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        assertThrows(LogQueryException.class, () -> topicQuadro
+        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(null)
@@ -235,8 +234,8 @@ void quadroIncorrectOp3() {
 
     @Test
     void quadroInCorrectAgainTopic() {
-        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         null)
@@ -251,13 +250,13 @@ void quadroInCorrectAgainTopic() {
 
     @Test
     void quadroInCorrectOp4() {
-        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        final LogTopicQuadro topicQuadro = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        assertThrows(LogQueryException.class, () -> topicQuadro
+        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -269,13 +268,13 @@ void quadroInCorrectOp4() {
 
     @Test
     void quadroInCorrectOp5() {
-        final LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        final LogTopicQuadro topicQuadro = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        assertThrows(LogQueryException.class, () -> topicQuadro
+        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -287,13 +286,13 @@ void quadroInCorrectOp5() {
 
     @Test
     void quadroInCorrectOp6() {
-        LogTopicQuadro topicQuadro = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        LogTopicQuadro topicQuadro = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        assertThrows(LogQueryException.class, () -> topicQuadro
+        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -305,8 +304,8 @@ void quadroInCorrectOp6() {
 
     @Test
     void quadroInCorrectTopic() {
-        assertThrows(LogQueryException.class, () -> LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "",
                         "")
diff --git a/src/test/java/io/api/etherscan/logs/LogsApiTest.java b/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
similarity index 67%
rename from src/test/java/io/api/etherscan/logs/LogsApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
index e786e0c..0f90d37 100644
--- a/src/test/java/io/api/etherscan/logs/LogsApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
@@ -1,10 +1,9 @@
-package io.api.etherscan.logs;
+package io.goodforgod.api.etherscan.logs;
 
-import io.api.ApiRunner;
-import io.api.etherscan.model.Log;
-import io.api.etherscan.model.query.LogOp;
-import io.api.etherscan.model.query.impl.LogQuery;
-import io.api.etherscan.model.query.impl.LogQueryBuilder;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.model.Log;
+import io.goodforgod.api.etherscan.model.query.LogOp;
+import io.goodforgod.api.etherscan.model.query.LogQuery;
 import java.util.List;
 import java.util.stream.Stream;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -18,22 +17,22 @@
 class LogsApiTest extends ApiRunner {
 
     static Stream<Arguments> source() {
-        LogQuery single = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
+        LogQuery single = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .build();
 
-        LogQuery singleInvalidAddr = LogQueryBuilder.with("0x13990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
+        LogQuery singleInvalidAddr = LogQuery.builder("0x13990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .build();
 
-        LogQuery tupleAnd = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224)
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        LogQuery tupleAnd = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224)
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                 .setOpTopic0_1(LogOp.AND)
                 .build();
 
-        LogQuery tupleOr = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-                .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        LogQuery tupleOr = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+                .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000")
                 .setOpTopic0_1(LogOp.OR)
                 .build();
diff --git a/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java b/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
new file mode 100644
index 0000000..23d14a2
--- /dev/null
+++ b/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
@@ -0,0 +1,56 @@
+package io.goodforgod.api.etherscan.manager;
+
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.manager.impl.FakeRequestQueueManager;
+import io.goodforgod.api.etherscan.manager.impl.SemaphoreRequestQueueManager;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+
+import java.time.Duration;
+
+/**
+ * @author GoodforGod
+ * @since 03.11.2018
+ */
+class SemaphoreRequestQueueManagerTest extends ApiRunner {
+
+    @Test
+    void fakeManager() {
+        RequestQueueManager fakeManager = new FakeRequestQueueManager();
+        fakeManager.takeTurn();
+        fakeManager.takeTurn();
+        fakeManager.takeTurn();
+        fakeManager.takeTurn();
+        fakeManager.takeTurn();
+        fakeManager.takeTurn();
+        assertNotNull(fakeManager);
+    }
+
+    @Test
+    @Timeout(3500)
+    void queueManager() {
+        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(3));
+        requestQueueManager.takeTurn();
+        requestQueueManager.takeTurn();
+        assertNotNull(requestQueueManager);
+    }
+
+    @Test
+    @Timeout(4500)
+    void queueManagerWithDelay() {
+        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(2), Duration.ofSeconds(2));
+        requestQueueManager.takeTurn();
+        requestQueueManager.takeTurn();
+        assertNotNull(requestQueueManager);
+    }
+
+    @Test
+    void queueManagerTimeout() {
+        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(3));
+        requestQueueManager.takeTurn();
+        long start = System.currentTimeMillis();
+        requestQueueManager.takeTurn();
+        long end = System.currentTimeMillis();
+        assertEquals(3, Math.round((double) (end - start) / 1000));
+    }
+}
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
similarity index 76%
rename from src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
index faead19..64e3fe6 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
@@ -1,10 +1,10 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.core.impl.EtherScanApi;
-import io.api.etherscan.manager.impl.QueueManager;
-import io.api.etherscan.model.EthNetwork;
-import io.api.etherscan.model.proxy.BlockProxy;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.EthNetworks;
+import io.goodforgod.api.etherscan.EtherScanAPI;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -14,11 +14,12 @@
  */
 class ProxyBlockApiTest extends ApiRunner {
 
-    private final EtherScanApi api;
+    private final EtherScanAPI api;
 
     ProxyBlockApiTest() {
-        final QueueManager queueManager = new QueueManager(1, 5100L, 5100L, 0);
-        this.api = new EtherScanApi(getApiKey(), EthNetwork.MAINNET, queueManager);
+        final RequestQueueManager queueManager = RequestQueueManager.DEFAULT_KEY_QUEUE;
+        this.api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
+                .build();
     }
 
     @Test
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyBlockLastNoApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
similarity index 75%
rename from src/test/java/io/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
index f866b6a..c4f5e31 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
@@ -1,6 +1,6 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
+import io.goodforgod.api.etherscan.ApiRunner;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyBlockUncleApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTest.java
similarity index 83%
rename from src/test/java/io/api/etherscan/proxy/ProxyBlockUncleApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTest.java
index 67a8875..c575072 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyBlockUncleApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.model.proxy.BlockProxy;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTest.java
similarity index 54%
rename from src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTest.java
index 8cf46c9..67e7682 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTest.java
@@ -1,9 +1,9 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.error.InvalidDataHexException;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidDataHexException;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -23,14 +23,16 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class, () -> getApi().proxy().call("0xEEF46DB4855E25702F8237E8f403FddcaF931C0",
-                "0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().proxy().call("0xEEF46DB4855E25702F8237E8f403FddcaF931C0",
+                        "0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724"));
     }
 
     @Test
     void invalidParamNotHex() {
-        assertThrows(InvalidDataHexException.class, () -> getApi().proxy().call("0xAEEF46DB4855E25702F8237E8f403FddcaF931C0",
-                "7-0a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724"));
+        assertThrows(EtherScanInvalidDataHexException.class,
+                () -> getApi().proxy().call("0xAEEF46DB4855E25702F8237E8f403FddcaF931C0",
+                        "7-0a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724"));
     }
 
     @Test
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTest.java
similarity index 66%
rename from src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTest.java
index 6835f07..c9dab25 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
-import io.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -21,7 +21,8 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class, () -> getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c"));
     }
 
     @Test
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyGasApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTest.java
similarity index 79%
rename from src/test/java/io/api/etherscan/proxy/ProxyGasApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTest.java
index b4b6f37..1b40705 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyGasApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidDataHexException;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidDataHexException;
 import java.math.BigInteger;
 import org.junit.jupiter.api.Test;
 
@@ -38,6 +38,6 @@ void correctEstimatedWithData() {
     @Test
     void invalidParamWithError() {
         String dataCustom = "280&60106000396000f360606040526000";
-        assertThrows(InvalidDataHexException.class, () -> getApi().proxy().gasEstimated(dataCustom));
+        assertThrows(EtherScanInvalidDataHexException.class, () -> getApi().proxy().gasEstimated(dataCustom));
     }
 }
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTest.java
similarity index 76%
rename from src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTest.java
index 6d2e8e4..2580e22 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -19,7 +19,7 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class,
+        assertThrows(EtherScanInvalidAddressException.class,
                 () -> getApi().proxy().storageAt("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0));
     }
 
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTest.java
similarity index 88%
rename from src/test/java/io/api/etherscan/proxy/ProxyTxApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTest.java
index decf95f..d6790bd 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidTxHashException;
-import io.api.etherscan.model.proxy.TxProxy;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidTxHashException;
+import io.goodforgod.api.etherscan.model.proxy.TxProxy;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -51,7 +51,7 @@ void correctByBlockNo() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidTxHashException.class,
+        assertThrows(EtherScanInvalidTxHashException.class,
                 () -> getApi().proxy().tx("0xe2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1"));
     }
 
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTest.java
similarity index 81%
rename from src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTest.java
index 0083f7a..a2327da 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -24,7 +24,7 @@ void correctByBlockNo() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class,
+        assertThrows(EtherScanInvalidAddressException.class,
                 () -> getApi().proxy().txSendCount("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd"));
     }
 
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxReceiptApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTest.java
similarity index 85%
rename from src/test/java/io/api/etherscan/proxy/ProxyTxReceiptApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTest.java
index 0159ed9..ba6370c 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxReceiptApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidTxHashException;
-import io.api.etherscan.model.proxy.ReceiptProxy;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidTxHashException;
+import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -39,7 +39,7 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidTxHashException.class, () -> getApi().proxy()
+        assertThrows(EtherScanInvalidTxHashException.class, () -> getApi().proxy()
                 .txReceipt("0xe2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1"));
     }
 
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxSendRawApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTest.java
similarity index 62%
rename from src/test/java/io/api/etherscan/proxy/ProxyTxSendRawApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTest.java
index 676dc3a..9f69060 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxSendRawApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.proxy;
+package io.goodforgod.api.etherscan.proxy;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.error.InvalidDataHexException;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidDataHexException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -21,12 +21,12 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidDataHexException.class, () -> getApi().proxy().txSendRaw("5151=0561"));
+        assertThrows(EtherScanInvalidDataHexException.class, () -> getApi().proxy().txSendRaw("5151=0561"));
     }
 
     @Test
     void invalidParamEtherScanDataException() {
-        assertThrows(EtherScanException.class, () -> getApi().proxy().txSendRaw("0x1"));
+        assertThrows(EtherScanResponseException.class, () -> getApi().proxy().txSendRaw("0x1"));
     }
 
     void correctParamWithEmptyExpectedResult() {
diff --git a/src/test/java/io/api/etherscan/statistic/StatisticPriceApiTest.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTest.java
similarity index 81%
rename from src/test/java/io/api/etherscan/statistic/StatisticPriceApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTest.java
index 9f89738..eb43b6e 100644
--- a/src/test/java/io/api/etherscan/statistic/StatisticPriceApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.statistic;
+package io.goodforgod.api.etherscan.statistic;
 
-import io.api.ApiRunner;
-import io.api.etherscan.model.Price;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.model.Price;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/src/test/java/io/api/etherscan/statistic/StatisticSupplyApiTest.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTest.java
similarity index 82%
rename from src/test/java/io/api/etherscan/statistic/StatisticSupplyApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTest.java
index 32c3018..c1e8e58 100644
--- a/src/test/java/io/api/etherscan/statistic/StatisticSupplyApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.statistic;
+package io.goodforgod.api.etherscan.statistic;
 
-import io.api.ApiRunner;
-import io.api.etherscan.model.Supply;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.model.Supply;
 import java.math.BigInteger;
 import org.junit.jupiter.api.Test;
 
diff --git a/src/test/java/io/api/etherscan/statistic/StatisticTokenSupplyApiTest.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
similarity index 67%
rename from src/test/java/io/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
index aefb2bd..84c086a 100644
--- a/src/test/java/io/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.statistic;
+package io.goodforgod.api.etherscan.statistic;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidAddressException;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
 import java.math.BigInteger;
 import org.junit.jupiter.api.Test;
 
@@ -20,7 +20,8 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidAddressException.class, () -> getApi().stats().supply("0x7d90b64a1a57749b0f932f1a3395792e12e7055"));
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().stats().supply("0x7d90b64a1a57749b0f932f1a3395792e12e7055"));
     }
 
     @Test
diff --git a/src/test/java/io/api/support/AddressUtil.java b/src/test/java/io/goodforgod/api/etherscan/support/AddressUtil.java
similarity index 98%
rename from src/test/java/io/api/support/AddressUtil.java
rename to src/test/java/io/goodforgod/api/etherscan/support/AddressUtil.java
index da04c37..fa007db 100644
--- a/src/test/java/io/api/support/AddressUtil.java
+++ b/src/test/java/io/goodforgod/api/etherscan/support/AddressUtil.java
@@ -1,4 +1,4 @@
-package io.api.support;
+package io.goodforgod.api.etherscan.support;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/test/java/io/api/etherscan/transaction/TransactionExecApiTest.java b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTest.java
similarity index 66%
rename from src/test/java/io/api/etherscan/transaction/TransactionExecApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTest.java
index de67a02..a2a5860 100644
--- a/src/test/java/io/api/etherscan/transaction/TransactionExecApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTest.java
@@ -1,8 +1,8 @@
-package io.api.etherscan.transaction;
+package io.goodforgod.api.etherscan.transaction;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidTxHashException;
-import io.api.etherscan.model.Status;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidTxHashException;
+import io.goodforgod.api.etherscan.model.Status;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -14,7 +14,7 @@ class TransactionExecApiTest extends ApiRunner {
 
     @Test
     void correct() {
-        Optional<Status> status = getApi().txs().execStatus("0x15f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a");
+        Optional<Status> status = getApi().txs().statusExec("0x15f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a");
         assertTrue(status.isPresent());
         assertTrue(status.get().haveError());
         assertNotNull(status.get().getErrDescription());
@@ -27,13 +27,13 @@ void correct() {
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidTxHashException.class,
-                () -> getApi().txs().execStatus("0xb513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b"));
+        assertThrows(EtherScanInvalidTxHashException.class,
+                () -> getApi().txs().statusExec("0xb513dd971aad228eb31f54489803639de167309ac72de68ecdaeb022a7ab42b"));
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        Optional<Status> status = getApi().txs().execStatus("0x55f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a");
+        Optional<Status> status = getApi().txs().statusExec("0x55f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a");
         assertTrue(status.isPresent());
         assertFalse(status.get().haveError());
     }
diff --git a/src/test/java/io/api/etherscan/transaction/TransactionReceiptApiTest.java b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTest.java
similarity index 61%
rename from src/test/java/io/api/etherscan/transaction/TransactionReceiptApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTest.java
index 94b93b3..83ca5af 100644
--- a/src/test/java/io/api/etherscan/transaction/TransactionReceiptApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTest.java
@@ -1,7 +1,7 @@
-package io.api.etherscan.transaction;
+package io.goodforgod.api.etherscan.transaction;
 
-import io.api.ApiRunner;
-import io.api.etherscan.error.InvalidTxHashException;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidTxHashException;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
@@ -14,21 +14,21 @@ class TransactionReceiptApiTest extends ApiRunner {
     @Test
     void correct() {
         Optional<Boolean> status = getApi().txs()
-                .receiptStatus("0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
+                .statusReceipt("0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
         assertTrue(status.isPresent());
         assertTrue(status.get());
     }
 
     @Test
     void invalidParamWithError() {
-        assertThrows(InvalidTxHashException.class,
-                () -> getApi().txs().receiptStatus("0x13c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76"));
+        assertThrows(EtherScanInvalidTxHashException.class,
+                () -> getApi().txs().statusReceipt("0x13c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76"));
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
         Optional<Boolean> status = getApi().txs()
-                .receiptStatus("0x113c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
+                .statusReceipt("0x113c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
         assertFalse(status.isPresent());
     }
 }
diff --git a/src/test/java/io/api/util/BasicUtilsTests.java b/src/test/java/io/goodforgod/api/etherscan/util/BasicUtilsTests.java
similarity index 75%
rename from src/test/java/io/api/util/BasicUtilsTests.java
rename to src/test/java/io/goodforgod/api/etherscan/util/BasicUtilsTests.java
index 36c22cb..90a2933 100644
--- a/src/test/java/io/api/util/BasicUtilsTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/util/BasicUtilsTests.java
@@ -1,11 +1,11 @@
-package io.api.util;
+package io.goodforgod.api.etherscan.util;
 
-import static io.api.etherscan.util.BasicUtils.*;
+import static io.goodforgod.api.etherscan.util.BasicUtils.*;
 
 import com.google.gson.Gson;
-import io.api.ApiRunner;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.model.utility.StringResponseTO;
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import java.util.ArrayList;
 import java.util.List;
 import org.junit.jupiter.api.Test;
@@ -21,7 +21,7 @@ void responseValidateEmpty() {
         String response = "{\"status\":\"0\",\"message\":\"No ether\",\"result\":\"status\"}";
         StringResponseTO responseTO = new Gson().fromJson(response, StringResponseTO.class);
 
-        assertThrows(EtherScanException.class, () -> validateTxResponse(responseTO));
+        assertThrows(EtherScanResponseException.class, () -> validateTxResponse(responseTO));
     }
 
     @Test
@@ -77,12 +77,12 @@ void isNotHexInvalid() {
     @Test
     void isResponseStatusInvalidThrows() {
         StringResponseTO responseTO = new StringResponseTO();
-        assertThrows(EtherScanException.class, () -> validateTxResponse(responseTO));
+        assertThrows(EtherScanResponseException.class, () -> validateTxResponse(responseTO));
     }
 
     @Test
     void isResponseNullThrows() {
         StringResponseTO responseTO = null;
-        assertThrows(EtherScanException.class, () -> validateTxResponse(responseTO));
+        assertThrows(EtherScanResponseException.class, () -> validateTxResponse(responseTO));
     }
 }

From 420c68f201128dc60f854ef60572c0bdd5877faa Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sat, 13 May 2023 20:47:09 +0300
Subject: [PATCH 14/67] [2.0.0-SNAPSHOT] GasTrackerAPI refactored to new API
 EthHttpClient package refactoring

---
 .../goodforgod/api/etherscan/AccountAPI.java  | 14 +++----
 .../api/etherscan/AccountAPIProvider.java     | 13 ++++---
 .../api/etherscan/BasicProvider.java          |  8 ++--
 .../api/etherscan/EtherScanAPI.java           |  4 ++
 .../api/etherscan/EtherScanAPIProvider.java   | 23 +++++++----
 .../api/etherscan/GasTrackerAPI.java          | 24 ++++++++++++
 .../api/etherscan/GasTrackerAPIProvider.java  | 37 ++++++++++++++++++
 .../api/etherscan/GasTrackerApiProvider.java  | 39 -------------------
 .../api/etherscan/IGasTrackerApi.java         | 23 -----------
 .../api/etherscan/model/BlockUncle.java       |  1 -
 .../api/etherscan/model/GasOracle.java        | 15 ++++---
 .../model/response/GasOracleResponseTO.java   |  6 +--
 .../account/AccountTxRc721TokenTest.java      |  4 +-
 .../SemaphoreRequestQueueManagerTest.java     |  6 +--
 14 files changed, 113 insertions(+), 104 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/GasTrackerApiProvider.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/IGasTrackerApi.java
 rename src/main/java/io/{ => goodforgod}/api/etherscan/model/GasOracle.java (79%)

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
index 1baefc9..40da2eb 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
@@ -112,21 +112,21 @@ public interface AccountAPI {
     /**
      * All ERC-20 token txs for given address and contract address
      *
-     * @param address    get txs for
+     * @param address         get txs for
      * @param contractAddress contract address to get txs for
-     * @param startBlock tx from this blockNumber
-     * @param endBlock   tx to this blockNumber
+     * @param startBlock      tx from this blockNumber
+     * @param endBlock        tx to this blockNumber
      * @return txs for address
-     * @throws ApiException parent exception class
+     * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxToken> txsToken(String address, String contractAddress, long startBlock, long endBlock) throws ApiException;
+    List<TxERC20> txsERC20(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxToken> txsToken(String address, String contractAddress, long startBlock) throws ApiException;
+    List<TxERC20> txsERC20(String address, String contractAddress, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxToken> txsToken(String address, String contractAddress) throws ApiException;
+    List<TxERC20> txsERC20(String address, String contractAddress) throws EtherScanException;
 
     /**
      * All ERC-721 (NFT) token txs for given address
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index e884399..3cc5409 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -234,19 +234,20 @@ public List<TxERC20> txsERC20(String address, long startBlock, long endBlock) th
 
     @NotNull
     @Override
-    public List<TxToken> txsToken(final String address, final String contractAddress) throws ApiException {
-        return txsToken(address, contractAddress, MIN_START_BLOCK);
+    public List<TxERC20> txsERC20(String address, String contractAddress) throws EtherScanException {
+        return txsERC20(address, contractAddress, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxToken> txsToken(final String address, final String contractAddress, final long startBlock) throws ApiException {
-        return txsToken(address, contractAddress, startBlock, MAX_END_BLOCK);
+    public List<TxERC20> txsERC20(String address, String contractAddress, long startBlock) throws EtherScanException {
+        return txsERC20(address, contractAddress, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxToken> txsToken(final String address, final String contractAddress, final long startBlock, final long endBlock) throws ApiException {
+    public List<TxERC20> txsERC20(String address, String contractAddress, long startBlock, long endBlock)
+            throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
@@ -255,7 +256,7 @@ public List<TxToken> txsToken(final String address, final String contractAddress
         final String urlParams = ACT_TX_TOKEN_ACTION + offsetParam + ADDRESS_PARAM + address
                 + CONTRACT_PARAM + contractAddress + blockParam + SORT_ASC_PARAM;
 
-        return getRequestUsingOffset(urlParams, TxTokenResponseTO.class);
+        return getRequestUsingOffset(urlParams, TxERC20ResponseTO.class);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 4fd625a..ec5a85a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -32,14 +32,14 @@ abstract class BasicProvider {
     private final RequestQueueManager queue;
     private final Gson gson;
 
-    BasicProvider(RequestQueueManager queue,
+    BasicProvider(RequestQueueManager requestQueueManager,
                   String module,
                   String baseUrl,
-                  EthHttpClient executor) {
-        this.queue = queue;
+                  EthHttpClient ethHttpClient) {
+        this.queue = requestQueueManager;
         this.module = "&module=" + module;
         this.baseUrl = baseUrl;
-        this.executor = executor;
+        this.executor = ethHttpClient;
         this.gson = new GsonConfiguration().builder().create();
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
index 76dcab7..d902074 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -34,6 +34,10 @@ public interface EtherScanAPI extends AutoCloseable {
     @NotNull
     StatisticAPI stats();
 
+    @NotNull
+    GasTrackerAPI gasTracker();
+
+    @NotNull
     static Builder builder() {
         return new EthScanAPIBuilder();
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
index 0043e37..675836f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
@@ -21,23 +21,25 @@ final class EtherScanAPIProvider implements EtherScanAPI {
     private final ProxyAPI proxy;
     private final StatisticAPI stats;
     private final TransactionAPI txs;
+    private final GasTrackerAPI gasTracker;
 
     EtherScanAPIProvider(String apiKey,
                          EthNetwork network,
                          Supplier<EthHttpClient> executorSupplier,
                          RequestQueueManager queue) {
         // EtherScan 1request\5sec limit support by queue manager
-        final EthHttpClient executor = executorSupplier.get();
+        final EthHttpClient ethHttpClient = executorSupplier.get();
         final String baseUrl = network.domain() + "?apikey=" + apiKey;
 
         this.requestQueueManager = queue;
-        this.account = new AccountAPIProvider(queue, baseUrl, executor);
-        this.block = new BlockAPIProvider(queue, baseUrl, executor);
-        this.contract = new ContractAPIProvider(queue, baseUrl, executor);
-        this.logs = new LogsAPIProvider(queue, baseUrl, executor);
-        this.proxy = new ProxyAPIProvider(queue, baseUrl, executor);
-        this.stats = new StatisticAPIProvider(queue, baseUrl, executor);
-        this.txs = new TransactionAPIProvider(queue, baseUrl, executor);
+        this.account = new AccountAPIProvider(queue, baseUrl, ethHttpClient);
+        this.block = new BlockAPIProvider(queue, baseUrl, ethHttpClient);
+        this.contract = new ContractAPIProvider(queue, baseUrl, ethHttpClient);
+        this.logs = new LogsAPIProvider(queue, baseUrl, ethHttpClient);
+        this.proxy = new ProxyAPIProvider(queue, baseUrl, ethHttpClient);
+        this.stats = new StatisticAPIProvider(queue, baseUrl, ethHttpClient);
+        this.txs = new TransactionAPIProvider(queue, baseUrl, ethHttpClient);
+        this.gasTracker = new GasTrackerAPIProvider(queue, baseUrl, ethHttpClient);
     }
 
     @NotNull
@@ -82,6 +84,11 @@ public StatisticAPI stats() {
         return stats;
     }
 
+    @Override
+    public @NotNull GasTrackerAPI gasTracker() {
+        return gasTracker;
+    }
+
     @Override
     public void close() throws Exception {
         requestQueueManager.close();
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
new file mode 100644
index 0000000..d49e14f
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
@@ -0,0 +1,24 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.GasOracle;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * EtherScan - API Descriptions
+ * <a href="https://docs.etherscan.io/api-endpoints/gas-tracker">...</a>
+ *
+ * @author Abhay Gupta
+ * @since 14.11.2022
+ */
+public interface GasTrackerAPI {
+
+    /**
+     * GasOracle details
+     *
+     * @return fast, suggested gas price
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    GasOracle oracle() throws EtherScanException;
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
new file mode 100644
index 0000000..faa01e5
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
@@ -0,0 +1,37 @@
+package io.goodforgod.api.etherscan;
+
+import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
+import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.GasOracle;
+import io.goodforgod.api.etherscan.model.response.GasOracleResponseTO;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * GasTracker API Implementation
+ *
+ * @see GasTrackerAPI
+ * @author Abhay Gupta
+ * @since 14.11.2022
+ */
+final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI {
+
+    private static final String ACT_GAS_ORACLE_PARAM = ACT_PREFIX + "gasoracle";
+
+    GasTrackerAPIProvider(RequestQueueManager queue,
+                          String baseUrl,
+                          EthHttpClient ethHttpClient) {
+        super(queue, "gastracker", baseUrl, ethHttpClient);
+    }
+
+    @NotNull
+    @Override
+    public GasOracle oracle() throws EtherScanException {
+        final GasOracleResponseTO response = getRequest(ACT_GAS_ORACLE_PARAM, GasOracleResponseTO.class);
+        if (response.getStatus() != 1)
+            throw new EtherScanResponseException(response);
+
+        return response.getResult();
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerApiProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerApiProvider.java
deleted file mode 100644
index 16d2e63..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerApiProvider.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package io.api.etherscan.core.impl;
-
-import io.api.etherscan.core.IGasTrackerApi;
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.error.EtherScanException;
-import io.api.etherscan.executor.IHttpExecutor;
-import io.api.etherscan.manager.IQueueManager;
-import io.api.etherscan.model.GasOracle;
-import io.api.etherscan.model.utility.GasOracleResponseTO;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * GasTracker API Implementation
- *
- * @see IGasTrackerApi
- *
- * @author Abhay Gupta
- * @since 14.11.2022
- */
-public class GasTrackerApiProvider extends BasicProvider implements IGasTrackerApi {
-
-    private static final String ACT_GAS_ORACLE_PARAM = ACT_PREFIX + "gasoracle";
-
-    GasTrackerApiProvider(final IQueueManager queue,
-                          final String baseUrl,
-                          final IHttpExecutor executor) {
-        super(queue, "gastracker", baseUrl, executor);
-    }
-
-    @NotNull
-    @Override
-    public GasOracle gasoracle() throws ApiException {
-        final GasOracleResponseTO response = getRequest(ACT_GAS_ORACLE_PARAM, GasOracleResponseTO.class);
-        if (response.getStatus() != 1)
-            throw new EtherScanException(response);
-
-        return response.getResult();
-    }
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/IGasTrackerApi.java b/src/main/java/io/goodforgod/api/etherscan/IGasTrackerApi.java
deleted file mode 100644
index 894713f..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/IGasTrackerApi.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package io.api.etherscan.core;
-
-import io.api.etherscan.error.ApiException;
-import io.api.etherscan.model.GasOracle;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * EtherScan - API Descriptions https://docs.etherscan.io/api-endpoints/gas-tracker
- *
- * @author Abhay Gupta
- * @since 14.11.2022
- */
-public interface IGasTrackerApi {
-
-    /**
-     * GasOracle details
-     *
-     * @return fast, suggested gas price
-     * @throws ApiException parent exception class
-     */
-    @NotNull
-    GasOracle gasoracle() throws ApiException;
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
index 34f8f30..add3bd1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
@@ -1,7 +1,6 @@
 package io.goodforgod.api.etherscan.model;
 
 import io.goodforgod.api.etherscan.util.BasicUtils;
-
 import java.math.BigInteger;
 import java.util.List;
 
diff --git a/src/main/java/io/api/etherscan/model/GasOracle.java b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
similarity index 79%
rename from src/main/java/io/api/etherscan/model/GasOracle.java
rename to src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
index f3f66c2..0ea1715 100644
--- a/src/main/java/io/api/etherscan/model/GasOracle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
@@ -1,15 +1,14 @@
-package io.api.etherscan.model;
+package io.goodforgod.api.etherscan.model;
 
 import java.math.BigInteger;
 import java.util.Objects;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author Abhay Gupta
  * @since 14.11.2022
  */
 public class GasOracle {
+
     private Long LastBlock;
     private Integer SafeGasPrice;
     private Integer ProposeGasPrice;
@@ -43,10 +42,14 @@ public String getGasUsedRatio() {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
         GasOracle gasOracle = (GasOracle) o;
-        return LastBlock.equals(gasOracle.LastBlock) && SafeGasPrice.equals(gasOracle.SafeGasPrice) && ProposeGasPrice.equals(gasOracle.ProposeGasPrice) && FastGasPrice.equals(gasOracle.FastGasPrice) && suggestBaseFee.equals(gasOracle.suggestBaseFee) && gasUsedRatio.equals(gasOracle.gasUsedRatio);
+        return LastBlock.equals(gasOracle.LastBlock) && SafeGasPrice.equals(gasOracle.SafeGasPrice)
+                && ProposeGasPrice.equals(gasOracle.ProposeGasPrice) && FastGasPrice.equals(gasOracle.FastGasPrice)
+                && suggestBaseFee.equals(gasOracle.suggestBaseFee) && gasUsedRatio.equals(gasOracle.gasUsedRatio);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/GasOracleResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/GasOracleResponseTO.java
index f0c1fd5..751854c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/GasOracleResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/GasOracleResponseTO.java
@@ -1,10 +1,8 @@
-package io.api.etherscan.model.utility;
+package io.goodforgod.api.etherscan.model.response;
 
-import io.api.etherscan.model.GasOracle;
+import io.goodforgod.api.etherscan.model.GasOracle;
 
 /**
- * ! NO DESCRIPTION !
- *
  * @author Abhay Gupta
  * @since 14.11.2022
  */
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
index c85aaa4..31c8533 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
@@ -2,10 +2,8 @@
 
 import io.goodforgod.api.etherscan.ApiRunner;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
-import io.goodforgod.api.etherscan.model.TxERC20;
-import java.util.List;
-
 import io.goodforgod.api.etherscan.model.TxERC721;
+import java.util.List;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java b/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
index 23d14a2..0d6daf6 100644
--- a/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
@@ -3,11 +3,10 @@
 import io.goodforgod.api.etherscan.ApiRunner;
 import io.goodforgod.api.etherscan.manager.impl.FakeRequestQueueManager;
 import io.goodforgod.api.etherscan.manager.impl.SemaphoreRequestQueueManager;
+import java.time.Duration;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
 
-import java.time.Duration;
-
 /**
  * @author GoodforGod
  * @since 03.11.2018
@@ -38,7 +37,8 @@ void queueManager() {
     @Test
     @Timeout(4500)
     void queueManagerWithDelay() {
-        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(2), Duration.ofSeconds(2));
+        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(2),
+                Duration.ofSeconds(2));
         requestQueueManager.takeTurn();
         requestQueueManager.takeTurn();
         assertNotNull(requestQueueManager);

From b9a8dda6d503b953d7e9aa7257a0d4e9bac2d351 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 00:50:20 +0300
Subject: [PATCH 15/67] [2.0.0-SNAPSHOT] Models builders added

---
 .../api/etherscan/AccountAPIProvider.java     |   2 +-
 .../api/etherscan/BasicProvider.java          |   2 +-
 .../impl/SemaphoreRequestQueueManager.java    |   5 +-
 .../goodforgod/api/etherscan/model/Abi.java   |  30 +++-
 .../api/etherscan/model/Balance.java          |   8 +-
 .../api/etherscan/model/BaseTx.java           |  22 +--
 .../goodforgod/api/etherscan/model/Block.java |  49 +++++-
 .../api/etherscan/model/BlockUncle.java       |  98 +++++++++++
 .../api/etherscan/model/GasOracle.java        |  57 +++++++
 .../goodforgod/api/etherscan/model/Log.java   |  93 +++++++++-
 .../goodforgod/api/etherscan/model/Price.java |  45 +++++
 .../api/etherscan/model/Status.java           |  29 ++++
 .../io/goodforgod/api/etherscan/model/Tx.java | 144 ++++++++++++++++
 .../api/etherscan/model/TxERC20.java          | 153 +++++++++++++++++
 .../api/etherscan/model/TxERC721.java         | 153 +++++++++++++++++
 .../api/etherscan/model/TxInternal.java       | 117 +++++++++++++
 .../goodforgod/api/etherscan/model/Wei.java   |   2 +-
 .../api/etherscan/model/proxy/BlockProxy.java | 160 ++++++++++++++++++
 .../etherscan/model/proxy/ReceiptProxy.java   | 103 +++++++++++
 .../api/etherscan/model/proxy/TxProxy.java    | 118 +++++++++++++
 20 files changed, 1361 insertions(+), 29 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 3cc5409..9160bb4 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -99,7 +99,7 @@ public List<Balance> balances(List<String> addresses) throws EtherScanException
 
             if (!BasicUtils.isEmpty(response.getResult()))
                 balances.addAll(response.getResult().stream()
-                        .map(Balance::of)
+                        .map(r -> new Balance(r.getAccount(), new BigInteger(r.getBalance())))
                         .collect(Collectors.toList()));
         }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index ec5a85a..a4ce2a6 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -1,6 +1,6 @@
 package io.goodforgod.api.etherscan;
 
-import com.google.gson.*;
+import com.google.gson.Gson;
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanParseException;
 import io.goodforgod.api.etherscan.error.EtherScanRateLimitException;
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
index cfd745f..ff12cd1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
@@ -2,7 +2,10 @@
 
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import java.time.Duration;
-import java.util.concurrent.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Queue Semaphore implementation with size and reset time as params
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
index b575c56..3fce40a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
@@ -8,8 +8,8 @@
  */
 public class Abi {
 
-    private String contractAbi;
-    private boolean isVerified;
+    private final String contractAbi;
+    private final boolean isVerified;
 
     private Abi(String contractAbi, boolean isVerified) {
         this.contractAbi = contractAbi;
@@ -70,4 +70,30 @@ public String toString() {
                 ", isVerified=" + isVerified +
                 '}';
     }
+
+    public static AbiBuilder builder() {
+        return new AbiBuilder();
+    }
+
+    public static final class AbiBuilder {
+
+        private String contractAbi;
+        private boolean isVerified;
+
+        private AbiBuilder() {}
+
+        public AbiBuilder withContractAbi(String contractAbi) {
+            this.contractAbi = contractAbi;
+            return this;
+        }
+
+        public AbiBuilder withIsVerified(boolean isVerified) {
+            this.isVerified = isVerified;
+            return this;
+        }
+
+        public Abi build() {
+            return new Abi(contractAbi, isVerified);
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
index d147a2c..38379e6 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
@@ -1,6 +1,5 @@
 package io.goodforgod.api.etherscan.model;
 
-import io.goodforgod.api.etherscan.model.response.BalanceTO;
 import java.math.BigInteger;
 import java.util.Objects;
 
@@ -14,16 +13,11 @@ public class Balance {
     private final Wei balance;
     private final String address;
 
-    public Balance(final String address,
-                   final BigInteger balance) {
+    public Balance(String address, BigInteger balance) {
         this.address = address;
         this.balance = new Wei(balance);
     }
 
-    public static Balance of(BalanceTO balance) {
-        return new Balance(balance.getAccount(), new BigInteger(balance.getBalance()));
-    }
-
     // <editor-fold desc="Getters">
     public String getAddress() {
         return address;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
index 1fb53e1..e159d3b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
@@ -13,18 +13,18 @@
  */
 abstract class BaseTx {
 
-    private long blockNumber;
-    private String timeStamp;
+    long blockNumber;
+    String timeStamp;
     @Expose(deserialize = false, serialize = false)
-    private LocalDateTime _timeStamp;
-    private String hash;
-    private String from;
-    private String to;
-    private BigInteger value;
-    private String contractAddress;
-    private String input;
-    private BigInteger gas;
-    private BigInteger gasUsed;
+    LocalDateTime _timeStamp;
+    String hash;
+    String from;
+    String to;
+    BigInteger value;
+    String contractAddress;
+    String input;
+    BigInteger gas;
+    BigInteger gasUsed;
 
     // <editor-fold desc="Getter">
     public long getBlockNumber() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Block.java b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
index 8b652bb..129ca39 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Block.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
@@ -12,11 +12,11 @@
  */
 public class Block {
 
-    private long blockNumber;
-    private BigInteger blockReward;
-    private String timeStamp;
+    long blockNumber;
+    BigInteger blockReward;
+    String timeStamp;
     @Expose(deserialize = false, serialize = false)
-    private LocalDateTime _timeStamp;
+    LocalDateTime _timeStamp;
 
     // <editor-fold desc="Getter">
     public long getBlockNumber() {
@@ -60,4 +60,45 @@ public String toString() {
                 ", _timeStamp=" + _timeStamp +
                 '}';
     }
+
+    public static BlockBuilder builder() {
+        return new BlockBuilder();
+    }
+
+    public static class BlockBuilder {
+
+        private long blockNumber;
+        private BigInteger blockReward;
+        private LocalDateTime timeStamp;
+
+        BlockBuilder() {}
+
+        public static BlockBuilder aBlock() {
+            return new BlockBuilder();
+        }
+
+        public BlockBuilder withBlockNumber(long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public BlockBuilder withBlockReward(BigInteger blockReward) {
+            this.blockReward = blockReward;
+            return this;
+        }
+
+        public BlockBuilder withTimeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public Block build() {
+            Block block = new Block();
+            block.blockNumber = this.blockNumber;
+            block.blockReward = this.blockReward;
+            block._timeStamp = this.timeStamp;
+            block.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            return block;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
index add3bd1..5cf1a3e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
@@ -2,6 +2,8 @@
 
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 import java.util.List;
 
 /**
@@ -69,6 +71,42 @@ public String toString() {
                     ", unclePosition=" + unclePosition +
                     '}';
         }
+
+        public static UncleBuilder builder() {
+            return new UncleBuilder();
+        }
+
+        public static final class UncleBuilder {
+
+            private String miner;
+            private BigInteger blockreward;
+            private int unclePosition;
+
+            private UncleBuilder() {}
+
+            public UncleBuilder withMiner(String miner) {
+                this.miner = miner;
+                return this;
+            }
+
+            public UncleBuilder withBlockreward(BigInteger blockreward) {
+                this.blockreward = blockreward;
+                return this;
+            }
+
+            public UncleBuilder withUnclePosition(int unclePosition) {
+                this.unclePosition = unclePosition;
+                return this;
+            }
+
+            public Uncle build() {
+                Uncle uncle = new Uncle();
+                uncle.miner = this.miner;
+                uncle.blockreward = this.blockreward;
+                uncle.unclePosition = this.unclePosition;
+                return uncle;
+            }
+        }
     }
 
     private String blockMiner;
@@ -124,4 +162,64 @@ public String toString() {
                 ", uncleInclusionReward='" + uncleInclusionReward + '\'' +
                 '}';
     }
+
+    public static BlockUncleBuilder builder() {
+        return new BlockUncleBuilder();
+    }
+
+    public static final class BlockUncleBuilder extends Block.BlockBuilder {
+
+        private long blockNumber;
+        private BigInteger blockReward;
+        private LocalDateTime timeStamp;
+        private String blockMiner;
+        private List<Uncle> uncles;
+        private String uncleInclusionReward;
+
+        private BlockUncleBuilder() {
+            super();
+        }
+
+        public BlockUncleBuilder withBlockNumber(long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public BlockUncleBuilder withBlockReward(BigInteger blockReward) {
+            this.blockReward = blockReward;
+            return this;
+        }
+
+        public BlockUncleBuilder withTimeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public BlockUncleBuilder withBlockMiner(String blockMiner) {
+            this.blockMiner = blockMiner;
+            return this;
+        }
+
+        public BlockUncleBuilder withUncles(List<Uncle> uncles) {
+            this.uncles = uncles;
+            return this;
+        }
+
+        public BlockUncleBuilder withUncleInclusionReward(String uncleInclusionReward) {
+            this.uncleInclusionReward = uncleInclusionReward;
+            return this;
+        }
+
+        public BlockUncle build() {
+            BlockUncle blockUncle = new BlockUncle();
+            blockUncle.uncles = this.uncles;
+            blockUncle.uncleInclusionReward = this.uncleInclusionReward;
+            blockUncle.blockNumber = this.blockNumber;
+            blockUncle.blockReward = this.blockReward;
+            blockUncle.blockMiner = this.blockMiner;
+            blockUncle._timeStamp = this.timeStamp;
+            blockUncle.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            return blockUncle;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
index 0ea1715..69fa6b5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
@@ -68,4 +68,61 @@ public String toString() {
                 ", gasUsedRatio='" + gasUsedRatio + '\'' +
                 '}';
     }
+
+    public static GasOracleBuilder builder() {
+        return new GasOracleBuilder();
+    }
+
+    public static final class GasOracleBuilder {
+
+        private Long LastBlock;
+        private Integer SafeGasPrice;
+        private Integer ProposeGasPrice;
+        private Integer FastGasPrice;
+        private Double suggestBaseFee;
+        private String gasUsedRatio;
+
+        private GasOracleBuilder() {}
+
+        public GasOracleBuilder withLastBlock(Long LastBlock) {
+            this.LastBlock = LastBlock;
+            return this;
+        }
+
+        public GasOracleBuilder withSafeGasPrice(Integer SafeGasPrice) {
+            this.SafeGasPrice = SafeGasPrice;
+            return this;
+        }
+
+        public GasOracleBuilder withProposeGasPrice(Integer ProposeGasPrice) {
+            this.ProposeGasPrice = ProposeGasPrice;
+            return this;
+        }
+
+        public GasOracleBuilder withFastGasPrice(Integer FastGasPrice) {
+            this.FastGasPrice = FastGasPrice;
+            return this;
+        }
+
+        public GasOracleBuilder withSuggestBaseFee(Double suggestBaseFee) {
+            this.suggestBaseFee = suggestBaseFee;
+            return this;
+        }
+
+        public GasOracleBuilder withGasUsedRatio(String gasUsedRatio) {
+            this.gasUsedRatio = gasUsedRatio;
+            return this;
+        }
+
+        public GasOracle build() {
+            GasOracle gasOracle = new GasOracle();
+            gasOracle.ProposeGasPrice = this.ProposeGasPrice;
+            gasOracle.LastBlock = this.LastBlock;
+            gasOracle.suggestBaseFee = this.suggestBaseFee;
+            gasOracle.SafeGasPrice = this.SafeGasPrice;
+            gasOracle.FastGasPrice = this.FastGasPrice;
+            gasOracle.gasUsedRatio = this.gasUsedRatio;
+            return gasOracle;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index cc22b66..bd03103 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -74,7 +74,7 @@ public LocalDateTime getTimeStamp() {
     /**
      * Return the "timeStamp" field of the event record as a long-int representing the milliseconds
      * since the Unix epoch (1970-01-01 00:00:00).
-     * 
+     *
      * @return milliseconds between Unix epoch and `timeStamp`. If field is empty or null, returns null
      */
     public Long getTimeStampAsMillis() {
@@ -180,4 +180,95 @@ public String toString() {
                 ", _logIndex=" + _logIndex +
                 '}';
     }
+
+    public static LogBuilder builder() {
+        return new LogBuilder();
+    }
+
+    public static final class LogBuilder {
+
+        private Long blockNumber;
+        private String address;
+        private String transactionHash;
+        private Long transactionIndex;
+        private LocalDateTime timeStamp;
+        private String data;
+        private BigInteger gasPrice;
+        private BigInteger gasUsed;
+        private List<String> topics;
+        private Long logIndex;
+
+        private LogBuilder() {}
+
+        public LogBuilder withBlockNumber(Long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public LogBuilder withAddress(String address) {
+            this.address = address;
+            return this;
+        }
+
+        public LogBuilder withTransactionHash(String transactionHash) {
+            this.transactionHash = transactionHash;
+            return this;
+        }
+
+        public LogBuilder withTransactionIndex(Long transactionIndex) {
+            this.transactionIndex = transactionIndex;
+            return this;
+        }
+
+        public LogBuilder withTimeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public LogBuilder withData(String data) {
+            this.data = data;
+            return this;
+        }
+
+        public LogBuilder withGasPrice(BigInteger gasPrice) {
+            this.gasPrice = gasPrice;
+            return this;
+        }
+
+        public LogBuilder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public LogBuilder withTopics(List<String> topics) {
+            this.topics = topics;
+            return this;
+        }
+
+        public LogBuilder withLogIndex(Long logIndex) {
+            this.logIndex = logIndex;
+            return this;
+        }
+
+        public Log build() {
+            Log log = new Log();
+            log.address = this.address;
+            log.gasPrice = String.valueOf(this.gasPrice);
+            log._gasPrice = this.gasPrice;
+            log._logIndex = this.logIndex;
+            log._transactionIndex = this.transactionIndex;
+            log._gasUsed = this.gasUsed;
+            log.blockNumber = String.valueOf(this.blockNumber);
+            log.transactionIndex = String.valueOf(this.transactionIndex);
+            log.timeStamp = String.valueOf(this.timeStamp);
+            log.data = this.data;
+            log.gasUsed = String.valueOf(this.gasUsed);
+            log._timeStamp = this.timeStamp;
+            log.logIndex = String.valueOf(this.logIndex);
+            log._blockNumber = this.blockNumber;
+            log.topics = this.topics;
+            log.transactionHash = this.transactionHash;
+            return log;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
index 712dbd8..9c72792 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -87,4 +87,49 @@ public String toString() {
                 ", ethbtc_timestamp='" + ethbtc_timestamp + '\'' +
                 '}';
     }
+
+    public static PriceBuilder builder() {
+        return new PriceBuilder();
+    }
+
+    public static final class PriceBuilder {
+
+        private double ethusd;
+        private double ethbtc;
+        private LocalDateTime ethusdTimestamp;
+        private LocalDateTime ethbtcTimestamp;
+
+        private PriceBuilder() {}
+
+        public PriceBuilder withEthusd(double ethusd) {
+            this.ethusd = ethusd;
+            return this;
+        }
+
+        public PriceBuilder withEthbtc(double ethbtc) {
+            this.ethbtc = ethbtc;
+            return this;
+        }
+
+        public PriceBuilder withEthusdTimestamp(LocalDateTime ethusdTimestamp) {
+            this.ethusdTimestamp = ethusdTimestamp;
+            return this;
+        }
+
+        public PriceBuilder withEthbtcTimestamp(LocalDateTime ethbtcTimestamp) {
+            this.ethbtcTimestamp = ethbtcTimestamp;
+            return this;
+        }
+
+        public Price build() {
+            Price price = new Price();
+            price.ethbtc = this.ethbtc;
+            price.ethbtc_timestamp = String.valueOf(this.ethbtcTimestamp.toEpochSecond(ZoneOffset.UTC));
+            price._ethbtc_timestamp = this.ethbtcTimestamp;
+            price.ethusd = this.ethusd;
+            price.ethusd_timestamp = String.valueOf(this.ethusdTimestamp.toEpochSecond(ZoneOffset.UTC));
+            price._ethusd_timestamp = this.ethusdTimestamp;
+            return price;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Status.java b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
index 274080a..8cdc704 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Status.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
@@ -54,4 +54,33 @@ public String toString() {
                 ", errDescription='" + errDescription + '\'' +
                 '}';
     }
+
+    public static StatusBuilder builder() {
+        return new StatusBuilder();
+    }
+
+    public static final class StatusBuilder {
+
+        private int isError;
+        private String errDescription;
+
+        private StatusBuilder() {}
+
+        public StatusBuilder withIsError(int isError) {
+            this.isError = isError;
+            return this;
+        }
+
+        public StatusBuilder withErrDescription(String errDescription) {
+            this.errDescription = errDescription;
+            return this;
+        }
+
+        public Status build() {
+            Status status = new Status();
+            status.isError = this.isError;
+            status.errDescription = this.errDescription;
+            return status;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 3ab0923..cc9be41 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -2,6 +2,8 @@
 
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 import java.util.Objects;
 
 /**
@@ -100,4 +102,146 @@ public String toString() {
                 ", txreceipt_status='" + txreceipt_status + '\'' +
                 "} " + super.toString();
     }
+
+    public static TxBuilder builder() {
+        return new TxBuilder();
+    }
+
+    public static final class TxBuilder {
+
+        private long blockNumber;
+        private LocalDateTime timeStamp;
+        private String hash;
+        private String from;
+        private String to;
+        private BigInteger value;
+        private String contractAddress;
+        private String input;
+        private BigInteger gas;
+        private BigInteger gasUsed;
+        private long nonce;
+        private String blockHash;
+        private int transactionIndex;
+        private BigInteger gasPrice;
+        private BigInteger cumulativeGasUsed;
+        private long confirmations;
+        private String isError;
+        private String txreceiptStatus;
+
+        private TxBuilder() {}
+
+        public TxBuilder withBlockNumber(long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public TxBuilder withTimeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public TxBuilder withHash(String hash) {
+            this.hash = hash;
+            return this;
+        }
+
+        public TxBuilder withFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        public TxBuilder withTo(String to) {
+            this.to = to;
+            return this;
+        }
+
+        public TxBuilder withValue(BigInteger value) {
+            this.value = value;
+            return this;
+        }
+
+        public TxBuilder withContractAddress(String contractAddress) {
+            this.contractAddress = contractAddress;
+            return this;
+        }
+
+        public TxBuilder withInput(String input) {
+            this.input = input;
+            return this;
+        }
+
+        public TxBuilder withGas(BigInteger gas) {
+            this.gas = gas;
+            return this;
+        }
+
+        public TxBuilder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public TxBuilder withNonce(long nonce) {
+            this.nonce = nonce;
+            return this;
+        }
+
+        public TxBuilder withBlockHash(String blockHash) {
+            this.blockHash = blockHash;
+            return this;
+        }
+
+        public TxBuilder withTransactionIndex(int transactionIndex) {
+            this.transactionIndex = transactionIndex;
+            return this;
+        }
+
+        public TxBuilder withGasPrice(BigInteger gasPrice) {
+            this.gasPrice = gasPrice;
+            return this;
+        }
+
+        public TxBuilder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
+            this.cumulativeGasUsed = cumulativeGasUsed;
+            return this;
+        }
+
+        public TxBuilder withConfirmations(long confirmations) {
+            this.confirmations = confirmations;
+            return this;
+        }
+
+        public TxBuilder withIsError(String isError) {
+            this.isError = isError;
+            return this;
+        }
+
+        public TxBuilder withTxreceiptStatus(String txreceiptStatus) {
+            this.txreceiptStatus = txreceiptStatus;
+            return this;
+        }
+
+        public Tx build() {
+            Tx tx = new Tx();
+            tx.gas = this.gas;
+            tx.isError = this.isError;
+            tx.blockHash = this.blockHash;
+            tx.hash = this.hash;
+            tx.gasUsed = this.gasUsed;
+            tx.from = this.from;
+            tx.txreceipt_status = this.txreceiptStatus;
+            tx.contractAddress = this.contractAddress;
+            tx.value = this.value;
+            tx.transactionIndex = this.transactionIndex;
+            tx.confirmations = this.confirmations;
+            tx.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            tx.nonce = this.nonce;
+            tx.blockNumber = this.blockNumber;
+            tx._timeStamp = this.timeStamp;
+            tx.to = this.to;
+            tx.input = this.input;
+            tx.cumulativeGasUsed = this.cumulativeGasUsed;
+            tx.gasPrice = this.gasPrice;
+            return tx;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
index 9f65d98..42ffebe 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
@@ -1,5 +1,9 @@
 package io.goodforgod.api.etherscan.model;
 
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
 /**
  * @author GoodforGod
  * @since 28.10.2018
@@ -68,4 +72,153 @@ public String toString() {
                 ", confirmations=" + confirmations +
                 "} " + super.toString();
     }
+
+    public static TxERC20Builder builder() {
+        return new TxERC20Builder();
+    }
+
+    public static final class TxERC20Builder {
+
+        private long blockNumber;
+        private LocalDateTime timeStamp;
+        private String hash;
+        private String from;
+        private String to;
+        private BigInteger value;
+        private String contractAddress;
+        private String input;
+        private BigInteger gas;
+        private BigInteger gasUsed;
+        private long nonce;
+        private String blockHash;
+        private String tokenName;
+        private String tokenSymbol;
+        private String tokenDecimal;
+        private int transactionIndex;
+        private long gasPrice;
+        private long cumulativeGasUsed;
+        private long confirmations;
+
+        private TxERC20Builder() {}
+
+        public TxERC20Builder withBlockNumber(long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public TxERC20Builder withTimeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public TxERC20Builder withHash(String hash) {
+            this.hash = hash;
+            return this;
+        }
+
+        public TxERC20Builder withFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        public TxERC20Builder withTo(String to) {
+            this.to = to;
+            return this;
+        }
+
+        public TxERC20Builder withValue(BigInteger value) {
+            this.value = value;
+            return this;
+        }
+
+        public TxERC20Builder withContractAddress(String contractAddress) {
+            this.contractAddress = contractAddress;
+            return this;
+        }
+
+        public TxERC20Builder withInput(String input) {
+            this.input = input;
+            return this;
+        }
+
+        public TxERC20Builder withGas(BigInteger gas) {
+            this.gas = gas;
+            return this;
+        }
+
+        public TxERC20Builder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public TxERC20Builder withNonce(long nonce) {
+            this.nonce = nonce;
+            return this;
+        }
+
+        public TxERC20Builder withBlockHash(String blockHash) {
+            this.blockHash = blockHash;
+            return this;
+        }
+
+        public TxERC20Builder withTokenName(String tokenName) {
+            this.tokenName = tokenName;
+            return this;
+        }
+
+        public TxERC20Builder withTokenSymbol(String tokenSymbol) {
+            this.tokenSymbol = tokenSymbol;
+            return this;
+        }
+
+        public TxERC20Builder withTokenDecimal(String tokenDecimal) {
+            this.tokenDecimal = tokenDecimal;
+            return this;
+        }
+
+        public TxERC20Builder withTransactionIndex(int transactionIndex) {
+            this.transactionIndex = transactionIndex;
+            return this;
+        }
+
+        public TxERC20Builder withGasPrice(long gasPrice) {
+            this.gasPrice = gasPrice;
+            return this;
+        }
+
+        public TxERC20Builder withCumulativeGasUsed(long cumulativeGasUsed) {
+            this.cumulativeGasUsed = cumulativeGasUsed;
+            return this;
+        }
+
+        public TxERC20Builder withConfirmations(long confirmations) {
+            this.confirmations = confirmations;
+            return this;
+        }
+
+        public TxERC20 build() {
+            TxERC20 txERC20 = new TxERC20();
+            txERC20.gas = this.gas;
+            txERC20.tokenName = this.tokenName;
+            txERC20.hash = this.hash;
+            txERC20.gasUsed = this.gasUsed;
+            txERC20.cumulativeGasUsed = this.cumulativeGasUsed;
+            txERC20.from = this.from;
+            txERC20.tokenSymbol = this.tokenSymbol;
+            txERC20.transactionIndex = this.transactionIndex;
+            txERC20.contractAddress = this.contractAddress;
+            txERC20.nonce = this.nonce;
+            txERC20.confirmations = this.confirmations;
+            txERC20.value = this.value;
+            txERC20.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            txERC20.blockHash = this.blockHash;
+            txERC20.blockNumber = this.blockNumber;
+            txERC20._timeStamp = this.timeStamp;
+            txERC20.gasPrice = this.gasPrice;
+            txERC20.to = this.to;
+            txERC20.input = this.input;
+            txERC20.tokenDecimal = this.tokenDecimal;
+            return txERC20;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
index 5b30314..14777fc 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
@@ -1,5 +1,9 @@
 package io.goodforgod.api.etherscan.model;
 
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
 /**
  * @author GoodforGod
  * @since 28.10.2018
@@ -68,4 +72,153 @@ public String toString() {
                 ", confirmations=" + confirmations +
                 "} " + super.toString();
     }
+
+    public static TxERC721Builder builder() {
+        return new TxERC721Builder();
+    }
+
+    public static final class TxERC721Builder {
+
+        private long blockNumber;
+        private LocalDateTime timeStamp;
+        private String hash;
+        private String from;
+        private String to;
+        private BigInteger value;
+        private String contractAddress;
+        private String input;
+        private BigInteger gas;
+        private BigInteger gasUsed;
+        private long nonce;
+        private String blockHash;
+        private String tokenName;
+        private String tokenSymbol;
+        private String tokenDecimal;
+        private int transactionIndex;
+        private long gasPrice;
+        private long cumulativeGasUsed;
+        private long confirmations;
+
+        private TxERC721Builder() {}
+
+        public TxERC721Builder withBlockNumber(long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public TxERC721Builder withTimeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public TxERC721Builder withHash(String hash) {
+            this.hash = hash;
+            return this;
+        }
+
+        public TxERC721Builder withFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        public TxERC721Builder withTo(String to) {
+            this.to = to;
+            return this;
+        }
+
+        public TxERC721Builder withValue(BigInteger value) {
+            this.value = value;
+            return this;
+        }
+
+        public TxERC721Builder withContractAddress(String contractAddress) {
+            this.contractAddress = contractAddress;
+            return this;
+        }
+
+        public TxERC721Builder withInput(String input) {
+            this.input = input;
+            return this;
+        }
+
+        public TxERC721Builder withGas(BigInteger gas) {
+            this.gas = gas;
+            return this;
+        }
+
+        public TxERC721Builder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public TxERC721Builder withNonce(long nonce) {
+            this.nonce = nonce;
+            return this;
+        }
+
+        public TxERC721Builder withBlockHash(String blockHash) {
+            this.blockHash = blockHash;
+            return this;
+        }
+
+        public TxERC721Builder withTokenName(String tokenName) {
+            this.tokenName = tokenName;
+            return this;
+        }
+
+        public TxERC721Builder withTokenSymbol(String tokenSymbol) {
+            this.tokenSymbol = tokenSymbol;
+            return this;
+        }
+
+        public TxERC721Builder withTokenDecimal(String tokenDecimal) {
+            this.tokenDecimal = tokenDecimal;
+            return this;
+        }
+
+        public TxERC721Builder withTransactionIndex(int transactionIndex) {
+            this.transactionIndex = transactionIndex;
+            return this;
+        }
+
+        public TxERC721Builder withGasPrice(long gasPrice) {
+            this.gasPrice = gasPrice;
+            return this;
+        }
+
+        public TxERC721Builder withCumulativeGasUsed(long cumulativeGasUsed) {
+            this.cumulativeGasUsed = cumulativeGasUsed;
+            return this;
+        }
+
+        public TxERC721Builder withConfirmations(long confirmations) {
+            this.confirmations = confirmations;
+            return this;
+        }
+
+        public TxERC721 build() {
+            TxERC721 txERC721 = new TxERC721();
+            txERC721.gas = this.gas;
+            txERC721.tokenName = this.tokenName;
+            txERC721.hash = this.hash;
+            txERC721.gasUsed = this.gasUsed;
+            txERC721.nonce = this.nonce;
+            txERC721.from = this.from;
+            txERC721.gasPrice = this.gasPrice;
+            txERC721.contractAddress = this.contractAddress;
+            txERC721.cumulativeGasUsed = this.cumulativeGasUsed;
+            txERC721.value = this.value;
+            txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            txERC721.blockNumber = this.blockNumber;
+            txERC721._timeStamp = this.timeStamp;
+            txERC721.tokenDecimal = this.tokenDecimal;
+            txERC721.transactionIndex = this.transactionIndex;
+            txERC721.to = this.to;
+            txERC721.confirmations = this.confirmations;
+            txERC721.input = this.input;
+            txERC721.blockHash = this.blockHash;
+            txERC721.tokenSymbol = this.tokenSymbol;
+            return txERC721;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index 244e0b7..f1d1edf 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -1,5 +1,8 @@
 package io.goodforgod.api.etherscan.model;
 
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 import java.util.Objects;
 
 /**
@@ -74,4 +77,118 @@ public String toString() {
                 ", errCode='" + errCode + '\'' +
                 "} " + super.toString();
     }
+
+    public static TxInternalBuilder builder() {
+        return new TxInternalBuilder();
+    }
+
+    public static final class TxInternalBuilder {
+
+        private long blockNumber;
+        private LocalDateTime timeStamp;
+        private String hash;
+        private String from;
+        private String to;
+        private BigInteger value;
+        private String contractAddress;
+        private String input;
+        private BigInteger gas;
+        private BigInteger gasUsed;
+        private String type;
+        private String traceId;
+        private int isError;
+        private String errCode;
+
+        private TxInternalBuilder() {}
+
+        public TxInternalBuilder withBlockNumber(long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public TxInternalBuilder with_timeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public TxInternalBuilder withHash(String hash) {
+            this.hash = hash;
+            return this;
+        }
+
+        public TxInternalBuilder withFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        public TxInternalBuilder withTo(String to) {
+            this.to = to;
+            return this;
+        }
+
+        public TxInternalBuilder withValue(BigInteger value) {
+            this.value = value;
+            return this;
+        }
+
+        public TxInternalBuilder withContractAddress(String contractAddress) {
+            this.contractAddress = contractAddress;
+            return this;
+        }
+
+        public TxInternalBuilder withInput(String input) {
+            this.input = input;
+            return this;
+        }
+
+        public TxInternalBuilder withGas(BigInteger gas) {
+            this.gas = gas;
+            return this;
+        }
+
+        public TxInternalBuilder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public TxInternalBuilder withType(String type) {
+            this.type = type;
+            return this;
+        }
+
+        public TxInternalBuilder withTraceId(String traceId) {
+            this.traceId = traceId;
+            return this;
+        }
+
+        public TxInternalBuilder withIsError(int isError) {
+            this.isError = isError;
+            return this;
+        }
+
+        public TxInternalBuilder withErrCode(String errCode) {
+            this.errCode = errCode;
+            return this;
+        }
+
+        public TxInternal build() {
+            TxInternal txInternal = new TxInternal();
+            txInternal.gas = this.gas;
+            txInternal.hash = this.hash;
+            txInternal.gasUsed = this.gasUsed;
+            txInternal.traceId = this.traceId;
+            txInternal.type = this.type;
+            txInternal.from = this.from;
+            txInternal.contractAddress = this.contractAddress;
+            txInternal.value = this.value;
+            txInternal.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            txInternal.errCode = this.errCode;
+            txInternal.blockNumber = this.blockNumber;
+            txInternal._timeStamp = this.timeStamp;
+            txInternal.isError = this.isError;
+            txInternal.to = this.to;
+            txInternal.input = this.input;
+            return txInternal;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index 224a1cf..85dd3ab 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -9,7 +9,7 @@
  */
 public class Wei {
 
-    private BigInteger result;
+    private final BigInteger result;
 
     public Wei(BigInteger value) {
         this.result = value;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index 889cc0e..0e6ff3a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -205,4 +205,164 @@ public String toString() {
                 ", transactions=" + transactions +
                 '}';
     }
+
+    public static BlockProxyBuilder builder() {
+        return new BlockProxyBuilder();
+    }
+
+    public static final class BlockProxyBuilder {
+
+        private Long number;
+        private String hash;
+        private String parentHash;
+        private String stateRoot;
+        private Long size;
+        private String difficulty;
+        private String totalDifficulty;
+        private LocalDateTime timestamp;
+        private String miner;
+        private String nonce;
+        private String extraData;
+        private String logsBloom;
+        private String mixHash;
+        private BigInteger gasUsed;
+        private BigInteger gasLimit;
+        private String sha3Uncles;
+        private List<String> uncles;
+        private String receiptsRoot;
+        private String transactionsRoot;
+        private List<TxProxy> transactions;
+
+        private BlockProxyBuilder() {}
+
+        public BlockProxyBuilder withNumber(Long number) {
+            this.number = number;
+            return this;
+        }
+
+        public BlockProxyBuilder withHash(String hash) {
+            this.hash = hash;
+            return this;
+        }
+
+        public BlockProxyBuilder withParentHash(String parentHash) {
+            this.parentHash = parentHash;
+            return this;
+        }
+
+        public BlockProxyBuilder withStateRoot(String stateRoot) {
+            this.stateRoot = stateRoot;
+            return this;
+        }
+
+        public BlockProxyBuilder withSize(Long size) {
+            this.size = size;
+            return this;
+        }
+
+        public BlockProxyBuilder withDifficulty(String difficulty) {
+            this.difficulty = difficulty;
+            return this;
+        }
+
+        public BlockProxyBuilder withTotalDifficulty(String totalDifficulty) {
+            this.totalDifficulty = totalDifficulty;
+            return this;
+        }
+
+        public BlockProxyBuilder withTimestamp(LocalDateTime timestamp) {
+            this.timestamp = timestamp;
+            return this;
+        }
+
+        public BlockProxyBuilder withMiner(String miner) {
+            this.miner = miner;
+            return this;
+        }
+
+        public BlockProxyBuilder withNonce(String nonce) {
+            this.nonce = nonce;
+            return this;
+        }
+
+        public BlockProxyBuilder withExtraData(String extraData) {
+            this.extraData = extraData;
+            return this;
+        }
+
+        public BlockProxyBuilder withLogsBloom(String logsBloom) {
+            this.logsBloom = logsBloom;
+            return this;
+        }
+
+        public BlockProxyBuilder withMixHash(String mixHash) {
+            this.mixHash = mixHash;
+            return this;
+        }
+
+        public BlockProxyBuilder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public BlockProxyBuilder withGasLimit(BigInteger gasLimit) {
+            this.gasLimit = gasLimit;
+            return this;
+        }
+
+        public BlockProxyBuilder withSha3Uncles(String sha3Uncles) {
+            this.sha3Uncles = sha3Uncles;
+            return this;
+        }
+
+        public BlockProxyBuilder withUncles(List<String> uncles) {
+            this.uncles = uncles;
+            return this;
+        }
+
+        public BlockProxyBuilder withReceiptsRoot(String receiptsRoot) {
+            this.receiptsRoot = receiptsRoot;
+            return this;
+        }
+
+        public BlockProxyBuilder withTransactionsRoot(String transactionsRoot) {
+            this.transactionsRoot = transactionsRoot;
+            return this;
+        }
+
+        public BlockProxyBuilder withTransactions(List<TxProxy> transactions) {
+            this.transactions = transactions;
+            return this;
+        }
+
+        public BlockProxy build() {
+            BlockProxy blockProxy = new BlockProxy();
+            blockProxy.mixHash = this.mixHash;
+            blockProxy.totalDifficulty = this.totalDifficulty;
+            blockProxy.nonce = this.nonce;
+            blockProxy._gasUsed = this.gasUsed;
+            blockProxy.uncles = this.uncles;
+            blockProxy.transactionsRoot = this.transactionsRoot;
+            blockProxy.number = String.valueOf(this.number);
+            blockProxy.logsBloom = this.logsBloom;
+            blockProxy.receiptsRoot = this.receiptsRoot;
+            blockProxy._gasLimit = this.gasLimit;
+            blockProxy.hash = this.hash;
+            blockProxy.parentHash = this.parentHash;
+            blockProxy._size = this.size;
+            blockProxy.gasLimit = String.valueOf(this.gasLimit);
+            blockProxy.difficulty = this.difficulty;
+            blockProxy.gasUsed = String.valueOf(this.gasUsed);
+            blockProxy.size = String.valueOf(this.size);
+            blockProxy.extraData = this.extraData;
+            blockProxy.stateRoot = this.stateRoot;
+            blockProxy._timestamp = this.timestamp;
+            blockProxy.sha3Uncles = this.sha3Uncles;
+            blockProxy.miner = this.miner;
+            blockProxy.timestamp = String.valueOf(this.timestamp.toEpochSecond(ZoneOffset.UTC));
+            blockProxy.transactions = this.transactions;
+            blockProxy._number = this.number;
+            return blockProxy;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index f4f7845..73a21b6 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -149,4 +149,107 @@ public String toString() {
                 ", logsBloom='" + logsBloom + '\'' +
                 '}';
     }
+
+    public static ReceiptProxyBuilder builder() {
+        return new ReceiptProxyBuilder();
+    }
+
+    public static final class ReceiptProxyBuilder {
+
+        private String root;
+        private String from;
+        private String to;
+        private Long blockNumber;
+        private String blockHash;
+        private String transactionHash;
+        private Long transactionIndex;
+        private BigInteger gasUsed;
+        private BigInteger cumulativeGasUsed;
+        private String contractAddress;
+        private List<Log> logs;
+        private String logsBloom;
+
+        private ReceiptProxyBuilder() {}
+
+        public ReceiptProxyBuilder withRoot(String root) {
+            this.root = root;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withTo(String to) {
+            this.to = to;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withBlockNumber(Long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withBlockHash(String blockHash) {
+            this.blockHash = blockHash;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withTransactionHash(String transactionHash) {
+            this.transactionHash = transactionHash;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withTransactionIndex(Long transactionIndex) {
+            this.transactionIndex = transactionIndex;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
+            this.cumulativeGasUsed = cumulativeGasUsed;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withContractAddress(String contractAddress) {
+            this.contractAddress = contractAddress;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withLogs(List<Log> logs) {
+            this.logs = logs;
+            return this;
+        }
+
+        public ReceiptProxyBuilder withLogsBloom(String logsBloom) {
+            this.logsBloom = logsBloom;
+            return this;
+        }
+
+        public ReceiptProxy build() {
+            ReceiptProxy receiptProxy = new ReceiptProxy();
+            receiptProxy.logsBloom = this.logsBloom;
+            receiptProxy.transactionHash = this.transactionHash;
+            receiptProxy.blockNumber = String.valueOf(this.blockNumber);
+            receiptProxy.from = this.from;
+            receiptProxy._transactionIndex = this.transactionIndex;
+            receiptProxy.blockHash = this.blockHash;
+            receiptProxy.root = this.root;
+            receiptProxy.contractAddress = this.contractAddress;
+            receiptProxy.gasUsed = String.valueOf(this.gasUsed);
+            receiptProxy._gasUsed = this.gasUsed;
+            receiptProxy.logs = this.logs;
+            receiptProxy.cumulativeGasUsed = String.valueOf(this.cumulativeGasUsed);
+            receiptProxy.to = this.to;
+            receiptProxy.transactionIndex = String.valueOf(this.transactionIndex);
+            receiptProxy._blockNumber = this.blockNumber;
+            receiptProxy._cumulativeGasUsed = this.cumulativeGasUsed;
+            return receiptProxy;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index cf3199b..52fe41b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -163,4 +163,122 @@ public String toString() {
                 ", _blockNumber=" + _blockNumber +
                 '}';
     }
+
+    public static TxProxyBuilder builder() {
+        return new TxProxyBuilder();
+    }
+
+    public static final class TxProxyBuilder {
+
+        private String to;
+        private String hash;
+        private Long transactionIndex;
+        private String from;
+        private String v;
+        private String input;
+        private String s;
+        private String r;
+        private Long nonce;
+        private String value;
+        private BigInteger gas;
+        private BigInteger gasPrice;
+        private String blockHash;
+        private Long blockNumber;
+
+        private TxProxyBuilder() {}
+
+        public TxProxyBuilder withTo(String to) {
+            this.to = to;
+            return this;
+        }
+
+        public TxProxyBuilder withHash(String hash) {
+            this.hash = hash;
+            return this;
+        }
+
+        public TxProxyBuilder withTransactionIndex(Long transactionIndex) {
+            this.transactionIndex = transactionIndex;
+            return this;
+        }
+
+        public TxProxyBuilder withFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        public TxProxyBuilder withV(String v) {
+            this.v = v;
+            return this;
+        }
+
+        public TxProxyBuilder withInput(String input) {
+            this.input = input;
+            return this;
+        }
+
+        public TxProxyBuilder withS(String s) {
+            this.s = s;
+            return this;
+        }
+
+        public TxProxyBuilder withR(String r) {
+            this.r = r;
+            return this;
+        }
+
+        public TxProxyBuilder withNonce(Long nonce) {
+            this.nonce = nonce;
+            return this;
+        }
+
+        public TxProxyBuilder withValue(String value) {
+            this.value = value;
+            return this;
+        }
+
+        public TxProxyBuilder withGas(BigInteger gas) {
+            this.gas = gas;
+            return this;
+        }
+
+        public TxProxyBuilder withGasPrice(BigInteger gasPrice) {
+            this.gasPrice = gasPrice;
+            return this;
+        }
+
+        public TxProxyBuilder withBlockHash(String blockHash) {
+            this.blockHash = blockHash;
+            return this;
+        }
+
+        public TxProxyBuilder withBlockNumber(Long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public TxProxy build() {
+            TxProxy txProxy = new TxProxy();
+            txProxy.input = this.input;
+            txProxy.gas = String.valueOf(this.gas);
+            txProxy._gas = this.gas;
+            txProxy.s = this.s;
+            txProxy.blockHash = this.blockHash;
+            txProxy.to = this.to;
+            txProxy.r = this.r;
+            txProxy.transactionIndex = String.valueOf(this.transactionIndex);
+            txProxy._nonce = this.nonce;
+            txProxy.value = this.value;
+            txProxy.v = this.v;
+            txProxy.from = this.from;
+            txProxy.nonce = String.valueOf(this.nonce);
+            txProxy._gasPrice = this.gasPrice;
+            txProxy._transactionIndex = this.transactionIndex;
+            txProxy.blockNumber = String.valueOf(this.blockNumber);
+            txProxy._blockNumber = this.blockNumber;
+            txProxy.hash = this.hash;
+            txProxy.gasPrice = String.valueOf(this.gasPrice);
+            return txProxy;
+        }
+    }
 }

From fe444f4ed8a16922cf06b31610947c95365ba22f Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 01:12:58 +0300
Subject: [PATCH 16/67] [2.0.0-SNAPSHOT] GasEstimate added to
 GasTrackerAPI#estimate

---
 .../api/etherscan/GasTrackerAPI.java          | 13 ++++-
 .../api/etherscan/GasTrackerAPIProvider.java  | 16 +++++++
 .../api/etherscan/model/GasEstimate.java      | 47 +++++++++++++++++++
 .../model/response/GasEstimateResponseTO.java | 14 ++++++
 4 files changed, 89 insertions(+), 1 deletion(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/GasEstimateResponseTO.java

diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
index d49e14f..355d62a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
@@ -1,7 +1,9 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.GasEstimate;
 import io.goodforgod.api.etherscan.model.GasOracle;
+import io.goodforgod.api.etherscan.model.Wei;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -14,7 +16,16 @@
 public interface GasTrackerAPI {
 
     /**
-     * GasOracle details
+     * Returns the estimated time, in seconds, for a transaction to be confirmed on the blockchain.
+     *
+     * @return fast, suggested gas price
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    GasEstimate estimate(@NotNull Wei wei) throws EtherScanException;
+
+    /**
+     * Returns the current Safe, Proposed and Fast gas prices.
      *
      * @return fast, suggested gas price
      * @throws EtherScanException parent exception class
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
index faa01e5..d4ec276 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
@@ -4,7 +4,10 @@
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import io.goodforgod.api.etherscan.executor.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.GasEstimate;
 import io.goodforgod.api.etherscan.model.GasOracle;
+import io.goodforgod.api.etherscan.model.Wei;
+import io.goodforgod.api.etherscan.model.response.GasEstimateResponseTO;
 import io.goodforgod.api.etherscan.model.response.GasOracleResponseTO;
 import org.jetbrains.annotations.NotNull;
 
@@ -18,6 +21,9 @@
 final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI {
 
     private static final String ACT_GAS_ORACLE_PARAM = ACT_PREFIX + "gasoracle";
+    private static final String ACT_GAS_ESTIMATE_PARAM = ACT_PREFIX + "gasestimate";
+
+    private static final String GASPRICE_PARAM = "&gasprice=";
 
     GasTrackerAPIProvider(RequestQueueManager queue,
                           String baseUrl,
@@ -25,6 +31,16 @@ final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI
         super(queue, "gastracker", baseUrl, ethHttpClient);
     }
 
+    @Override
+    public @NotNull GasEstimate estimate(@NotNull Wei wei) throws EtherScanException {
+        final String urlParams = ACT_GAS_ESTIMATE_PARAM + GASPRICE_PARAM + wei.getValue().toString();
+        final GasEstimateResponseTO response = getRequest(urlParams, GasEstimateResponseTO.class);
+        if (response.getStatus() != 1)
+            throw new EtherScanResponseException(response);
+
+        return new GasEstimate(Long.parseLong(response.getResult()));
+    }
+
     @NotNull
     @Override
     public GasOracle oracle() throws EtherScanException {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java b/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
new file mode 100644
index 0000000..7f1e61d
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
@@ -0,0 +1,47 @@
+package io.goodforgod.api.etherscan.model;
+
+import java.time.Duration;
+import java.util.Objects;
+
+/**
+ * @author GoodforGod
+ * @since 14.05.2023
+ */
+public class GasEstimate {
+
+    private final Duration duration;
+
+    public GasEstimate(long durationInSeconds) {
+        this.duration = Duration.ofSeconds(durationInSeconds);
+    }
+
+    public GasEstimate(Duration duration) {
+        this.duration = duration;
+    }
+
+    public Duration getDuration() {
+        return duration;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (!(o instanceof GasEstimate))
+            return false;
+        GasEstimate that = (GasEstimate) o;
+        return Objects.equals(duration, that.duration);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(duration);
+    }
+
+    @Override
+    public String toString() {
+        return "GasEstimate{" +
+                "duration=" + duration +
+                '}';
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/GasEstimateResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/GasEstimateResponseTO.java
new file mode 100644
index 0000000..96432f3
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/GasEstimateResponseTO.java
@@ -0,0 +1,14 @@
+package io.goodforgod.api.etherscan.model.response;
+
+/**
+ * @author Abhay Gupta
+ * @since 14.11.2022
+ */
+public class GasEstimateResponseTO extends BaseResponseTO {
+
+    private String result;
+
+    public String getResult() {
+        return result;
+    }
+}

From 192cb5b872e447c7f611044ca215e53619a07547 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 01:23:43 +0300
Subject: [PATCH 17/67] [2.0.0-SNAPSHOT] RequestQueueManager values renamed

---
 .../java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java  | 2 +-
 .../api/etherscan/manager/RequestQueueManager.java           | 5 +++--
 src/test/java/io/goodforgod/api/etherscan/ApiRunner.java     | 2 +-
 .../io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java | 2 +-
 4 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index d36d385..6571121 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -20,7 +20,7 @@ final class EthScanAPIBuilder implements EtherScanAPI.Builder {
 
     private String apiKey = DEFAULT_KEY;
     private EthNetwork ethNetwork = EthNetworks.MAINNET;
-    private RequestQueueManager queueManager = RequestQueueManager.DEFAULT_KEY_QUEUE;
+    private RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
     private Supplier<EthHttpClient> ethHttpClientSupplier = DEFAULT_SUPPLIER;
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index 7472c3f..d568601 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -12,9 +12,10 @@
  */
 public interface RequestQueueManager extends AutoCloseable {
 
-    RequestQueueManager DEFAULT_KEY_QUEUE = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5050L),
+    RequestQueueManager DEFAULT = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5050L),
             Duration.ofMillis(5050L), 0);
-    RequestQueueManager PERSONAL_KEY_QUEUE = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1050L),
+
+    RequestQueueManager PERSONAL = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1050L),
             Duration.ofMillis(1050L), 5);
 
     /**
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index 3b9cbe2..cd4a657 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -23,7 +23,7 @@ public class ApiRunner extends Assertions {
                 : key;
 
         final RequestQueueManager queueManager = (DEFAULT_KEY.equals(apiKey))
-                ? RequestQueueManager.DEFAULT_KEY_QUEUE
+                ? RequestQueueManager.DEFAULT
                 : new SemaphoreRequestQueueManager(1, Duration.ofMillis(1200L), Duration.ofMillis(1200L), 0);
 
         api = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
index 64e3fe6..e31aab8 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
@@ -17,7 +17,7 @@ class ProxyBlockApiTest extends ApiRunner {
     private final EtherScanAPI api;
 
     ProxyBlockApiTest() {
-        final RequestQueueManager queueManager = RequestQueueManager.DEFAULT_KEY_QUEUE;
+        final RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
         this.api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
                 .build();
     }

From 0cafb6df4518156bc914cb8adb40e41ff5fb3d85 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 02:17:12 +0300
Subject: [PATCH 18/67] [2.0.0-SNAPSHOT] TxErc1155 added AccountAPI#txsErc1155
 added AccountAPI#txsErc721 with contract added

---
 .../goodforgod/api/etherscan/AccountAPI.java  |  72 +++++-
 .../api/etherscan/AccountAPIProvider.java     | 122 ++++++++--
 .../goodforgod/api/etherscan/EthNetwork.java  |   3 +
 .../api/etherscan/model/BaseTx.java           |  41 +---
 .../io/goodforgod/api/etherscan/model/Tx.java |  33 +--
 .../api/etherscan/model/TxErc1155.java        | 230 ++++++++++++++++++
 .../model/{TxERC20.java => TxErc20.java}      |  12 +-
 .../model/{TxERC721.java => TxErc721.java}    |  26 +-
 .../api/etherscan/model/TxInternal.java       |  22 +-
 .../model/response/TxERC20ResponseTO.java     |  11 -
 .../model/response/TxERC721ResponseTO.java    |  11 -
 .../model/response/TxErc1155ResponseTO.java   |  11 +
 .../model/response/TxErc20ResponseTO.java     |  11 +
 .../model/response/TxErc721ResponseTO.java    |  11 +
 .../api/etherscan/util/BasicUtils.java        |   2 +-
 ...ERC20Test.java => AccountTxErc20Test.java} |  18 +-
 .../account/AccountTxRc1155TokenTest.java     |  81 ++++++
 .../account/AccountTxRc721TokenTest.java      |  16 +-
 18 files changed, 577 insertions(+), 156 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
 rename src/main/java/io/goodforgod/api/etherscan/model/{TxERC20.java => TxErc20.java} (96%)
 rename src/main/java/io/goodforgod/api/etherscan/model/{TxERC721.java => TxErc721.java} (93%)
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTxERC20Test.java => AccountTxErc20Test.java} (81%)
 create mode 100644 src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTest.java

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
index 40da2eb..294fb2a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
@@ -101,13 +101,13 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxERC20> txsERC20(String address, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxERC20> txsERC20(String address, long startBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxERC20> txsERC20(String address) throws EtherScanException;
+    List<TxErc20> txsErc20(String address) throws EtherScanException;
 
     /**
      * All ERC-20 token txs for given address and contract address
@@ -120,13 +120,13 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxERC20> txsERC20(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxERC20> txsERC20(String address, String contractAddress, long startBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(String address, String contractAddress, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxERC20> txsERC20(String address, String contractAddress) throws EtherScanException;
+    List<TxErc20> txsErc20(String address, String contractAddress) throws EtherScanException;
 
     /**
      * All ERC-721 (NFT) token txs for given address
@@ -138,13 +138,67 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxERC721> txsERC721(String address, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc721> txsErc721(String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxERC721> txsERC721(String address, long startBlock) throws EtherScanException;
+    List<TxErc721> txsErc721(String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxERC721> txsERC721(String address) throws EtherScanException;
+    List<TxErc721> txsErc721(String address) throws EtherScanException;
+
+    /**
+     * All ERC-721 (NFT) token txs for given address
+     *
+     * @param address    get txs for
+     * @param startBlock tx from this blockNumber
+     * @param endBlock   tx to this blockNumber
+     * @return txs for address
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    List<TxErc721> txsErc721(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
+
+    @NotNull
+    List<TxErc721> txsErc721(String address, String contractAddress, long startBlock) throws EtherScanException;
+
+    @NotNull
+    List<TxErc721> txsErc721(String address, String contractAddress) throws EtherScanException;
+
+    /**
+     * All ERC-721 (NFT) token txs for given address
+     *
+     * @param address    get txs for
+     * @param startBlock tx from this blockNumber
+     * @param endBlock   tx to this blockNumber
+     * @return txs for address
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    List<TxErc1155> txsErc1155(String address, long startBlock, long endBlock) throws EtherScanException;
+
+    @NotNull
+    List<TxErc1155> txsErc1155(String address, long startBlock) throws EtherScanException;
+
+    @NotNull
+    List<TxErc1155> txsErc1155(String address) throws EtherScanException;
+
+    /**
+     * All ERC-721 (NFT) token txs for given address
+     *
+     * @param address    get txs for
+     * @param startBlock tx from this blockNumber
+     * @param endBlock   tx to this blockNumber
+     * @return txs for address
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
+
+    @NotNull
+    List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock) throws EtherScanException;
+
+    @NotNull
+    List<TxErc1155> txsErc1155(String address, String contractAddress) throws EtherScanException;
 
     /**
      * All blocks mined by address
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 9160bb4..9382618 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -30,8 +30,9 @@ final class AccountAPIProvider extends BasicProvider implements AccountAPI {
     private static final String ACT_BALANCE_MULTI_ACTION = ACT_PREFIX + "balancemulti";
     private static final String ACT_TX_ACTION = ACT_PREFIX + "txlist";
     private static final String ACT_TX_INTERNAL_ACTION = ACT_PREFIX + "txlistinternal";
-    private static final String ACT_TX_TOKEN_ACTION = ACT_PREFIX + "tokentx";
-    private static final String ACT_TX_NFT_TOKEN_ACTION = ACT_PREFIX + "tokennfttx";
+    private static final String ACT_TX_ERC20_ACTION = ACT_PREFIX + "tokentx";
+    private static final String ACT_TX_ERC721_ACTION = ACT_PREFIX + "tokennfttx";
+    private static final String ACT_TX_ERC1155_ACTION = ACT_PREFIX + "token1155tx";
     private static final String ACT_MINED_ACTION = ACT_PREFIX + "getminedblocks";
 
     private static final String BLOCK_TYPE_PARAM = "&blocktype=blocks";
@@ -145,8 +146,7 @@ public List<Tx> txs(String address, long startBlock, long endBlock) throws Ether
      * @param <R>       responseListTO type
      * @return List of T values
      */
-    private <T, R extends BaseListResponseTO> List<T> getRequestUsingOffset(final String urlParams,
-                                                                            Class<R> tClass)
+    private <T, R extends BaseListResponseTO<T>> List<T> getRequestUsingOffset(final String urlParams, Class<R> tClass)
             throws EtherScanException {
         final List<T> result = new ArrayList<>();
         int page = 1;
@@ -208,81 +208,153 @@ public List<TxInternal> txsInternalByHash(String txhash) throws EtherScanExcepti
 
     @NotNull
     @Override
-    public List<TxERC20> txsERC20(String address) throws EtherScanException {
-        return txsERC20(address, MIN_START_BLOCK);
+    public List<TxErc20> txsErc20(String address) throws EtherScanException {
+        return txsErc20(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxERC20> txsERC20(String address, long startBlock) throws EtherScanException {
-        return txsERC20(address, startBlock, MAX_END_BLOCK);
+    public List<TxErc20> txsErc20(String address, long startBlock) throws EtherScanException {
+        return txsErc20(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxERC20> txsERC20(String address, long startBlock, long endBlock) throws EtherScanException {
+    public List<TxErc20> txsErc20(String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
-        final String urlParams = ACT_TX_TOKEN_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
+        final String urlParams = ACT_TX_ERC20_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
                 + ADDRESS_PARAM + address
                 + START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end()
                 + SORT_ASC_PARAM;
 
-        return getRequestUsingOffset(urlParams, TxERC20ResponseTO.class);
+        return getRequestUsingOffset(urlParams, TxErc20ResponseTO.class);
     }
 
     @NotNull
     @Override
-    public List<TxERC20> txsERC20(String address, String contractAddress) throws EtherScanException {
-        return txsERC20(address, contractAddress, MIN_START_BLOCK);
+    public List<TxErc20> txsErc20(String address, String contractAddress) throws EtherScanException {
+        return txsErc20(address, contractAddress, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxERC20> txsERC20(String address, String contractAddress, long startBlock) throws EtherScanException {
-        return txsERC20(address, contractAddress, startBlock, MAX_END_BLOCK);
+    public List<TxErc20> txsErc20(String address, String contractAddress, long startBlock) throws EtherScanException {
+        return txsErc20(address, contractAddress, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxERC20> txsERC20(String address, String contractAddress, long startBlock, long endBlock)
+    public List<TxErc20> txsErc20(String address, String contractAddress, long startBlock, long endBlock)
             throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
         final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
         final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
-        final String urlParams = ACT_TX_TOKEN_ACTION + offsetParam + ADDRESS_PARAM + address
+        final String urlParams = ACT_TX_ERC20_ACTION + offsetParam + ADDRESS_PARAM + address
                 + CONTRACT_PARAM + contractAddress + blockParam + SORT_ASC_PARAM;
 
-        return getRequestUsingOffset(urlParams, TxERC20ResponseTO.class);
+        return getRequestUsingOffset(urlParams, TxErc20ResponseTO.class);
     }
 
     @NotNull
     @Override
-    public List<TxERC721> txsERC721(String address) throws EtherScanException {
-        return txsERC721(address, MIN_START_BLOCK);
+    public List<TxErc721> txsErc721(String address) throws EtherScanException {
+        return txsErc721(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxERC721> txsERC721(String address, long startBlock) throws EtherScanException {
-        return txsERC721(address, startBlock, MAX_END_BLOCK);
+    public List<TxErc721> txsErc721(String address, long startBlock) throws EtherScanException {
+        return txsErc721(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxERC721> txsERC721(String address, long startBlock, long endBlock) throws EtherScanException {
+    public List<TxErc721> txsErc721(String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
-        final String urlParams = ACT_TX_NFT_TOKEN_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
+        final String urlParams = ACT_TX_ERC721_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
                 + ADDRESS_PARAM + address
                 + START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end()
                 + SORT_ASC_PARAM;
 
-        return getRequestUsingOffset(urlParams, TxERC20ResponseTO.class);
+        return getRequestUsingOffset(urlParams, TxErc721ResponseTO.class);
+    }
+
+    @Override
+    public @NotNull List<TxErc721> txsErc721(String address, String contractAddress, long startBlock, long endBlock)
+            throws EtherScanException {
+        BasicUtils.validateAddress(address);
+        final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
+
+        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
+        final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
+        final String urlParams = ACT_TX_ERC721_ACTION + offsetParam + ADDRESS_PARAM + address
+                + CONTRACT_PARAM + contractAddress + blockParam + SORT_ASC_PARAM;
+
+        return getRequestUsingOffset(urlParams, TxErc721ResponseTO.class);
+    }
+
+    @Override
+    public @NotNull List<TxErc721> txsErc721(String address, String contractAddress, long startBlock) throws EtherScanException {
+        return txsErc721(address, contractAddress, startBlock, MAX_END_BLOCK);
+    }
+
+    @Override
+    public @NotNull List<TxErc721> txsErc721(String address, String contractAddress) throws EtherScanException {
+        return txsErc721(address, contractAddress, MIN_START_BLOCK);
+    }
+
+    @Override
+    public @NotNull List<TxErc1155> txsErc1155(String address, long startBlock, long endBlock) throws EtherScanException {
+        BasicUtils.validateAddress(address);
+        final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
+
+        final String urlParams = ACT_TX_ERC1155_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX
+                + ADDRESS_PARAM + address
+                + START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end()
+                + SORT_ASC_PARAM;
+
+        return getRequestUsingOffset(urlParams, TxErc1155ResponseTO.class);
+    }
+
+    @Override
+    public @NotNull List<TxErc1155> txsErc1155(String address, long startBlock) throws EtherScanException {
+        return txsErc1155(address, startBlock, MAX_END_BLOCK);
+    }
+
+    @Override
+    public @NotNull List<TxErc1155> txsErc1155(String address) throws EtherScanException {
+        return txsErc1155(address, MIN_START_BLOCK);
+    }
+
+    @Override
+    public @NotNull List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock, long endBlock)
+            throws EtherScanException {
+        BasicUtils.validateAddress(address);
+        final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
+
+        final String offsetParam = PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX;
+        final String blockParam = START_BLOCK_PARAM + blocks.start() + END_BLOCK_PARAM + blocks.end();
+        final String urlParams = ACT_TX_ERC1155_ACTION + offsetParam + ADDRESS_PARAM + address
+                + CONTRACT_PARAM + contractAddress + blockParam + SORT_ASC_PARAM;
+
+        return getRequestUsingOffset(urlParams, TxErc1155ResponseTO.class);
+    }
+
+    @Override
+    public @NotNull List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock)
+            throws EtherScanException {
+        return txsErc1155(address, contractAddress, startBlock, MAX_END_BLOCK);
+    }
+
+    @Override
+    public @NotNull List<TxErc1155> txsErc1155(String address, String contractAddress) throws EtherScanException {
+        return txsErc1155(address, contractAddress, MIN_START_BLOCK);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthNetwork.java b/src/main/java/io/goodforgod/api/etherscan/EthNetwork.java
index ce0d929..96d8d0b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthNetwork.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthNetwork.java
@@ -9,6 +9,9 @@
  */
 public interface EthNetwork {
 
+    /**
+     * @return URI for network domain like <a href="https://api.etherscan.io/api">EtherScan API</a>
+     */
     @NotNull
     URI domain();
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
index e159d3b..c66e60f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
@@ -20,7 +20,6 @@ abstract class BaseTx {
     String hash;
     String from;
     String to;
-    BigInteger value;
     String contractAddress;
     String input;
     BigInteger gas;
@@ -49,10 +48,6 @@ public String getTo() {
         return to;
     }
 
-    public BigInteger getValue() {
-        return value;
-    }
-
     public String getContractAddress() {
         return contractAddress;
     }
@@ -76,41 +71,16 @@ public boolean equals(Object o) {
             return true;
         if (!(o instanceof BaseTx))
             return false;
-
         BaseTx baseTx = (BaseTx) o;
-
-        if (blockNumber != baseTx.blockNumber)
-            return false;
-        if (!Objects.equals(timeStamp, baseTx.timeStamp))
-            return false;
-        if (!Objects.equals(hash, baseTx.hash))
-            return false;
-        if (!Objects.equals(from, baseTx.from))
-            return false;
-        if (!Objects.equals(to, baseTx.to))
-            return false;
-        return Objects.equals(value, baseTx.value);
+        return blockNumber == baseTx.blockNumber && Objects.equals(timeStamp, baseTx.timeStamp)
+                && Objects.equals(hash, baseTx.hash) && Objects.equals(from, baseTx.from) && Objects.equals(to, baseTx.to)
+                && Objects.equals(contractAddress, baseTx.contractAddress) && Objects.equals(input, baseTx.input)
+                && Objects.equals(gas, baseTx.gas) && Objects.equals(gasUsed, baseTx.gasUsed);
     }
 
     @Override
     public int hashCode() {
-        int result = (int) (blockNumber ^ (blockNumber >>> 32));
-        result = 31 * result + (timeStamp != null
-                ? timeStamp.hashCode()
-                : 0);
-        result = 31 * result + (hash != null
-                ? hash.hashCode()
-                : 0);
-        result = 31 * result + (from != null
-                ? from.hashCode()
-                : 0);
-        result = 31 * result + (to != null
-                ? to.hashCode()
-                : 0);
-        result = 31 * result + (value != null
-                ? value.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(blockNumber, timeStamp, hash, from, to, contractAddress, input, gas, gasUsed);
     }
 
     @Override
@@ -121,7 +91,6 @@ public String toString() {
                 ", hash='" + hash + '\'' +
                 ", from='" + from + '\'' +
                 ", to='" + to + '\'' +
-                ", value=" + value +
                 ", contractAddress='" + contractAddress + '\'' +
                 ", input='" + input + '\'' +
                 ", gas=" + gas +
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index cc9be41..65c24ba 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -12,6 +12,7 @@
  */
 public class Tx extends BaseTx {
 
+    private BigInteger value;
     private long nonce;
     private String blockHash;
     private int transactionIndex;
@@ -22,6 +23,10 @@ public class Tx extends BaseTx {
     private String txreceipt_status;
 
     // <editor-fold desc="Getters">
+    public BigInteger getValue() {
+        return value;
+    }
+
     public long getNonce() {
         return nonce;
     }
@@ -59,40 +64,28 @@ public long getConfirmations() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Tx))
             return false;
         if (!super.equals(o))
             return false;
-
         Tx tx = (Tx) o;
-
-        if (nonce != tx.nonce)
-            return false;
-        if (transactionIndex != tx.transactionIndex)
-            return false;
-        if (!Objects.equals(blockHash, tx.blockHash))
-            return false;
-        return Objects.equals(isError, tx.isError);
+        return nonce == tx.nonce && transactionIndex == tx.transactionIndex && confirmations == tx.confirmations
+                && Objects.equals(value, tx.value) && Objects.equals(blockHash, tx.blockHash)
+                && Objects.equals(gasPrice, tx.gasPrice) && Objects.equals(cumulativeGasUsed, tx.cumulativeGasUsed)
+                && Objects.equals(isError, tx.isError) && Objects.equals(txreceipt_status, tx.txreceipt_status);
     }
 
     @Override
     public int hashCode() {
-        int result = super.hashCode();
-        result = 31 * result + (int) (nonce ^ (nonce >>> 32));
-        result = 31 * result + (blockHash != null
-                ? blockHash.hashCode()
-                : 0);
-        result = 31 * result + transactionIndex;
-        result = 31 * result + (isError != null
-                ? isError.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(super.hashCode(), value, nonce, blockHash, transactionIndex, gasPrice, cumulativeGasUsed,
+                confirmations, isError, txreceipt_status);
     }
 
     @Override
     public String toString() {
         return "Tx{" +
                 "nonce=" + nonce +
+                ", value='" + value + '\'' +
                 ", blockHash='" + blockHash + '\'' +
                 ", transactionIndex=" + transactionIndex +
                 ", gasPrice=" + gasPrice +
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
new file mode 100644
index 0000000..e57af5f
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -0,0 +1,230 @@
+package io.goodforgod.api.etherscan.model;
+
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+/**
+ * @author GoodforGod
+ * @since 28.10.2018
+ */
+public class TxErc1155 extends BaseTx {
+
+    private long nonce;
+    private String blockHash;
+    private String tokenID;
+    private String tokenName;
+    private String tokenSymbol;
+    private String tokenValue;
+    private int transactionIndex;
+    private long gasPrice;
+    private long cumulativeGasUsed;
+    private long confirmations;
+
+    // <editor-fold desc="Getters">
+    public long getNonce() {
+        return nonce;
+    }
+
+    public String getBlockHash() {
+        return blockHash;
+    }
+
+    public String getTokenID() {
+        return tokenID;
+    }
+
+    public String getTokenName() {
+        return tokenName;
+    }
+
+    public String getTokenSymbol() {
+        return tokenSymbol;
+    }
+
+    public String getTokenValue() {
+        return tokenValue;
+    }
+
+    public int getTransactionIndex() {
+        return transactionIndex;
+    }
+
+    public long getGasPrice() {
+        return gasPrice;
+    }
+
+    public long getCumulativeGasUsed() {
+        return cumulativeGasUsed;
+    }
+
+    public long getConfirmations() {
+        return confirmations;
+    }
+    // </editor-fold>
+
+    @Override
+    public String toString() {
+        return "TxERC721{" +
+                "nonce=" + nonce +
+                ", blockHash='" + blockHash + '\'' +
+                ", tokenID='" + tokenID + '\'' +
+                ", tokenName='" + tokenName + '\'' +
+                ", tokenSymbol='" + tokenSymbol + '\'' +
+                ", tokenValue='" + tokenValue + '\'' +
+                ", transactionIndex=" + transactionIndex +
+                ", gasPrice=" + gasPrice +
+                ", cumulativeGasUsed=" + cumulativeGasUsed +
+                ", confirmations=" + confirmations +
+                "} " + super.toString();
+    }
+
+    public static TxErc1155Builder builder() {
+        return new TxErc1155Builder();
+    }
+
+    public static final class TxErc1155Builder {
+
+        private long blockNumber;
+        private LocalDateTime timeStamp;
+        private String hash;
+        private String from;
+        private String to;
+        private String contractAddress;
+        private String input;
+        private BigInteger gas;
+        private BigInteger gasUsed;
+        private long nonce;
+        private String blockHash;
+        private String tokenID;
+        private String tokenName;
+        private String tokenSymbol;
+        private String tokenValue;
+        private int transactionIndex;
+        private long gasPrice;
+        private long cumulativeGasUsed;
+        private long confirmations;
+
+        private TxErc1155Builder() {}
+
+        public TxErc1155Builder withBlockNumber(long blockNumber) {
+            this.blockNumber = blockNumber;
+            return this;
+        }
+
+        public TxErc1155Builder withTimeStamp(LocalDateTime timeStamp) {
+            this.timeStamp = timeStamp;
+            return this;
+        }
+
+        public TxErc1155Builder withHash(String hash) {
+            this.hash = hash;
+            return this;
+        }
+
+        public TxErc1155Builder withFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        public TxErc1155Builder withTo(String to) {
+            this.to = to;
+            return this;
+        }
+
+        public TxErc1155Builder withContractAddress(String contractAddress) {
+            this.contractAddress = contractAddress;
+            return this;
+        }
+
+        public TxErc1155Builder withInput(String input) {
+            this.input = input;
+            return this;
+        }
+
+        public TxErc1155Builder withGas(BigInteger gas) {
+            this.gas = gas;
+            return this;
+        }
+
+        public TxErc1155Builder withGasUsed(BigInteger gasUsed) {
+            this.gasUsed = gasUsed;
+            return this;
+        }
+
+        public TxErc1155Builder withNonce(long nonce) {
+            this.nonce = nonce;
+            return this;
+        }
+
+        public TxErc1155Builder withBlockHash(String blockHash) {
+            this.blockHash = blockHash;
+            return this;
+        }
+
+        public TxErc1155Builder withTokenID(String tokenID) {
+            this.tokenID = tokenID;
+            return this;
+        }
+
+        public TxErc1155Builder withTokenName(String tokenName) {
+            this.tokenName = tokenName;
+            return this;
+        }
+
+        public TxErc1155Builder withTokenSymbol(String tokenSymbol) {
+            this.tokenSymbol = tokenSymbol;
+            return this;
+        }
+
+        public TxErc1155Builder withTokenDecimal(String tokenDecimal) {
+            this.tokenValue = tokenDecimal;
+            return this;
+        }
+
+        public TxErc1155Builder withTransactionIndex(int transactionIndex) {
+            this.transactionIndex = transactionIndex;
+            return this;
+        }
+
+        public TxErc1155Builder withGasPrice(long gasPrice) {
+            this.gasPrice = gasPrice;
+            return this;
+        }
+
+        public TxErc1155Builder withCumulativeGasUsed(long cumulativeGasUsed) {
+            this.cumulativeGasUsed = cumulativeGasUsed;
+            return this;
+        }
+
+        public TxErc1155Builder withConfirmations(long confirmations) {
+            this.confirmations = confirmations;
+            return this;
+        }
+
+        public TxErc1155 build() {
+            TxErc1155 txERC721 = new TxErc1155();
+            txERC721.gas = this.gas;
+            txERC721.tokenName = this.tokenName;
+            txERC721.hash = this.hash;
+            txERC721.gasUsed = this.gasUsed;
+            txERC721.nonce = this.nonce;
+            txERC721.from = this.from;
+            txERC721.gasPrice = this.gasPrice;
+            txERC721.contractAddress = this.contractAddress;
+            txERC721.cumulativeGasUsed = this.cumulativeGasUsed;
+            txERC721.tokenID = this.tokenID;
+            txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            txERC721.blockNumber = this.blockNumber;
+            txERC721._timeStamp = this.timeStamp;
+            txERC721.tokenValue = this.tokenValue;
+            txERC721.transactionIndex = this.transactionIndex;
+            txERC721.to = this.to;
+            txERC721.confirmations = this.confirmations;
+            txERC721.input = this.input;
+            txERC721.blockHash = this.blockHash;
+            txERC721.tokenSymbol = this.tokenSymbol;
+            return txERC721;
+        }
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
similarity index 96%
rename from src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
rename to src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index 42ffebe..da6f54f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxERC20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -8,8 +8,9 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class TxERC20 extends BaseTx {
+public class TxErc20 extends BaseTx {
 
+    private BigInteger value;
     private long nonce;
     private String blockHash;
     private String tokenName;
@@ -29,6 +30,10 @@ public String getBlockHash() {
         return blockHash;
     }
 
+    public BigInteger getValue() {
+        return value;
+    }
+
     public String getTokenName() {
         return tokenName;
     }
@@ -63,6 +68,7 @@ public String toString() {
         return "TxERC20{" +
                 "nonce=" + nonce +
                 ", blockHash='" + blockHash + '\'' +
+                ", value='" + value + '\'' +
                 ", tokenName='" + tokenName + '\'' +
                 ", tokenSymbol='" + tokenSymbol + '\'' +
                 ", tokenDecimal='" + tokenDecimal + '\'' +
@@ -196,8 +202,8 @@ public TxERC20Builder withConfirmations(long confirmations) {
             return this;
         }
 
-        public TxERC20 build() {
-            TxERC20 txERC20 = new TxERC20();
+        public TxErc20 build() {
+            TxErc20 txERC20 = new TxErc20();
             txERC20.gas = this.gas;
             txERC20.tokenName = this.tokenName;
             txERC20.hash = this.hash;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
similarity index 93%
rename from src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
rename to src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 14777fc..548113c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxERC721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -8,10 +8,11 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class TxERC721 extends BaseTx {
+public class TxErc721 extends BaseTx {
 
     private long nonce;
     private String blockHash;
+    private String tokenID;
     private String tokenName;
     private String tokenSymbol;
     private String tokenDecimal;
@@ -29,6 +30,10 @@ public String getBlockHash() {
         return blockHash;
     }
 
+    public String getTokenID() {
+        return tokenID;
+    }
+
     public String getTokenName() {
         return tokenName;
     }
@@ -63,6 +68,7 @@ public String toString() {
         return "TxERC721{" +
                 "nonce=" + nonce +
                 ", blockHash='" + blockHash + '\'' +
+                ", tokenID='" + tokenID + '\'' +
                 ", tokenName='" + tokenName + '\'' +
                 ", tokenSymbol='" + tokenSymbol + '\'' +
                 ", tokenDecimal='" + tokenDecimal + '\'' +
@@ -84,13 +90,13 @@ public static final class TxERC721Builder {
         private String hash;
         private String from;
         private String to;
-        private BigInteger value;
         private String contractAddress;
         private String input;
         private BigInteger gas;
         private BigInteger gasUsed;
         private long nonce;
         private String blockHash;
+        private String tokenID;
         private String tokenName;
         private String tokenSymbol;
         private String tokenDecimal;
@@ -126,11 +132,6 @@ public TxERC721Builder withTo(String to) {
             return this;
         }
 
-        public TxERC721Builder withValue(BigInteger value) {
-            this.value = value;
-            return this;
-        }
-
         public TxERC721Builder withContractAddress(String contractAddress) {
             this.contractAddress = contractAddress;
             return this;
@@ -161,6 +162,11 @@ public TxERC721Builder withBlockHash(String blockHash) {
             return this;
         }
 
+        public TxERC721Builder withTokenID(String tokenID) {
+            this.tokenID = tokenID;
+            return this;
+        }
+
         public TxERC721Builder withTokenName(String tokenName) {
             this.tokenName = tokenName;
             return this;
@@ -196,8 +202,8 @@ public TxERC721Builder withConfirmations(long confirmations) {
             return this;
         }
 
-        public TxERC721 build() {
-            TxERC721 txERC721 = new TxERC721();
+        public TxErc721 build() {
+            TxErc721 txERC721 = new TxErc721();
             txERC721.gas = this.gas;
             txERC721.tokenName = this.tokenName;
             txERC721.hash = this.hash;
@@ -207,7 +213,7 @@ public TxERC721 build() {
             txERC721.gasPrice = this.gasPrice;
             txERC721.contractAddress = this.contractAddress;
             txERC721.cumulativeGasUsed = this.cumulativeGasUsed;
-            txERC721.value = this.value;
+            txERC721.tokenID = this.tokenID;
             txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
             txERC721.blockNumber = this.blockNumber;
             txERC721._timeStamp = this.timeStamp;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index f1d1edf..84e10b3 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -11,12 +11,17 @@
  */
 public class TxInternal extends BaseTx {
 
+    private BigInteger value;
     private String type;
     private String traceId;
     private int isError;
     private String errCode;
 
     // <editor-fold desc="Getters">
+    public BigInteger getValue() {
+        return value;
+    }
+
     public String getType() {
         return type;
     }
@@ -48,24 +53,14 @@ public boolean equals(Object o) {
             return false;
         if (!super.equals(o))
             return false;
-
         TxInternal that = (TxInternal) o;
-
-        if (!Objects.equals(traceId, that.traceId))
-            return false;
-        return Objects.equals(errCode, that.errCode);
+        return isError == that.isError && Objects.equals(value, that.value) && Objects.equals(type, that.type)
+                && Objects.equals(traceId, that.traceId) && Objects.equals(errCode, that.errCode);
     }
 
     @Override
     public int hashCode() {
-        int result = super.hashCode();
-        result = 31 * result + (traceId != null
-                ? traceId.hashCode()
-                : 0);
-        result = 31 * result + (errCode != null
-                ? errCode.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(super.hashCode(), value, type, traceId, isError, errCode);
     }
 
     @Override
@@ -73,6 +68,7 @@ public String toString() {
         return "TxInternal{" +
                 "type='" + type + '\'' +
                 ", traceId=" + traceId +
+                ", value=" + value +
                 ", isError=" + isError +
                 ", errCode='" + errCode + '\'' +
                 "} " + super.toString();
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java
deleted file mode 100644
index f4814a5..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC20ResponseTO.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.goodforgod.api.etherscan.model.response;
-
-import io.goodforgod.api.etherscan.model.TxERC20;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class TxERC20ResponseTO extends BaseListResponseTO<TxERC20> {
-
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java
deleted file mode 100644
index b4db8ef..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/TxERC721ResponseTO.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.goodforgod.api.etherscan.model.response;
-
-import io.goodforgod.api.etherscan.model.TxERC20;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class TxERC721ResponseTO extends BaseListResponseTO<TxERC20> {
-
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
new file mode 100644
index 0000000..994d2cd
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxErc1155;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class TxErc1155ResponseTO extends BaseListResponseTO<TxErc1155> {
+
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
new file mode 100644
index 0000000..d5d3f6e
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxErc20;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class TxErc20ResponseTO extends BaseListResponseTO<TxErc20> {
+
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java
new file mode 100644
index 0000000..2a9403f
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxErc721;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class TxErc721ResponseTO extends BaseListResponseTO<TxErc721> {
+
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
index 4522ff5..eda3ce2 100644
--- a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
+++ b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
@@ -20,7 +20,7 @@ public final class BasicUtils {
 
     private BasicUtils() {}
 
-    private static final int MAX_END_BLOCK = 999999999;
+    private static final int MAX_END_BLOCK = Integer.MAX_VALUE;
     private static final int MIN_START_BLOCK = 0;
 
     private static final Pattern ADDRESS_PATTERN = Pattern.compile("0x[a-zA-Z0-9]{40}");
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxERC20Test.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Test.java
similarity index 81%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTxERC20Test.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Test.java
index bacf2e3..0a94289 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxERC20Test.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Test.java
@@ -2,7 +2,7 @@
 
 import io.goodforgod.api.etherscan.ApiRunner;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
-import io.goodforgod.api.etherscan.model.TxERC20;
+import io.goodforgod.api.etherscan.model.TxErc20;
 import java.util.List;
 import org.junit.jupiter.api.Test;
 
@@ -10,11 +10,11 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountTxERC20Test extends ApiRunner {
+class AccountTxErc20Test extends ApiRunner {
 
     @Test
     void correct() {
-        List<TxERC20> txs = getApi().account().txsERC20("0xE376F69ED2218076682e2b3B7b9099eC50aD68c4");
+        List<TxErc20> txs = getApi().account().txsErc20("0xE376F69ED2218076682e2b3B7b9099eC50aD68c4");
         assertNotNull(txs);
         assertEquals(3, txs.size());
         assertTxs(txs);
@@ -33,7 +33,7 @@ void correct() {
 
     @Test
     void correctStartBlock() {
-        List<TxERC20> txs = getApi().account().txsERC20("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167);
+        List<TxErc20> txs = getApi().account().txsErc20("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167);
         assertNotNull(txs);
         assertEquals(11, txs.size());
         assertTxs(txs);
@@ -41,7 +41,7 @@ void correctStartBlock() {
 
     @Test
     void correctStartBlockEndBlock() {
-        List<TxERC20> txs = getApi().account().txsERC20("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167, 5813576);
+        List<TxErc20> txs = getApi().account().txsErc20("0x36ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7", 5578167, 5813576);
         assertNotNull(txs);
         assertEquals(5, txs.size());
         assertTxs(txs);
@@ -50,18 +50,18 @@ void correctStartBlockEndBlock() {
     @Test
     void invalidParamWithError() {
         assertThrows(EtherScanInvalidAddressException.class,
-                () -> getApi().account().txsERC20("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
+                () -> getApi().account().txsErc20("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        List<TxERC20> txs = getApi().account().txsERC20("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
+        List<TxErc20> txs = getApi().account().txsErc20("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
     }
 
-    private void assertTxs(List<TxERC20> txs) {
-        for (TxERC20 tx : txs) {
+    private void assertTxs(List<TxErc20> txs) {
+        for (TxErc20 tx : txs) {
             assertNotNull(tx.getBlockHash());
             assertNotNull(tx.getTokenName());
             assertNotNull(tx.getTokenSymbol());
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTest.java
new file mode 100644
index 0000000..ce3a680
--- /dev/null
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTest.java
@@ -0,0 +1,81 @@
+package io.goodforgod.api.etherscan.account;
+
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.TxErc1155;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author GoodforGod
+ * @since 14.05.2023
+ */
+class AccountTxRc1155TokenTest extends ApiRunner {
+
+    @Test
+    void correct() {
+        List<TxErc1155> txs = getApi().account().txsErc1155("0xE4C8324534C0C6bCA174Cd0F02fAC9889C36bA59");
+        assertNotNull(txs);
+        assertFalse(txs.isEmpty());
+        assertTxs(txs);
+        assertNotEquals(0, txs.get(0).getGasPrice());
+        assertNotEquals(-1, txs.get(0).getNonce());
+
+        assertNotNull(txs.get(0).toString());
+        assertNotEquals(txs.get(0).toString(), txs.get(1).toString());
+
+        assertNotEquals(txs.get(0), txs.get(1));
+        assertNotEquals(txs.get(0).hashCode(), txs.get(1).hashCode());
+
+        assertEquals(txs.get(1), txs.get(1));
+        assertEquals(txs.get(1).hashCode(), txs.get(1).hashCode());
+    }
+
+    @Test
+    void correctStartBlock() {
+        List<TxErc1155> txs = getApi().account().txsErc1155("0xE4C8324534C0C6bCA174Cd0F02fAC9889C36bA59", 14275897);
+        assertNotNull(txs);
+        assertFalse(txs.isEmpty());
+        assertTxs(txs);
+    }
+
+    @Test
+    void correctStartBlockEndBlock() {
+        List<TxErc1155> txs = getApi().account().txsErc1155("0xE4C8324534C0C6bCA174Cd0F02fAC9889C36bA59", 14275897, 15148929);
+        assertNotNull(txs);
+        assertEquals(11, txs.size());
+        assertTxs(txs);
+    }
+
+    @Test
+    void invalidParamWithError() {
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().account().txsErc1155("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
+    }
+
+    @Test
+    void correctParamWithEmptyExpectedResult() {
+        List<TxErc1155> txs = getApi().account().txsErc1155("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
+        assertNotNull(txs);
+        assertTrue(txs.isEmpty());
+    }
+
+    private void assertTxs(List<TxErc1155> txs) {
+        txs.forEach(this::asserTx);
+    }
+
+    private void asserTx(TxErc1155 tx) {
+        assertNotNull(tx.getBlockHash());
+        assertNotNull(tx.getTokenName());
+        assertNotNull(tx.getTokenSymbol());
+        assertNotNull(tx.getFrom());
+        assertNotNull(tx.getTo());
+        assertNotNull(tx.getTimeStamp());
+        assertNotNull(tx.getTokenID());
+        assertNotNull(tx.getTokenValue());
+        assertNotEquals(-1, (tx.getConfirmations()));
+        assertNotNull(tx.getGasUsed());
+        assertNotEquals(-1, tx.getCumulativeGasUsed());
+        assertNotEquals(-1, tx.getTransactionIndex());
+    }
+}
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
index 31c8533..b7988db 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
@@ -2,7 +2,7 @@
 
 import io.goodforgod.api.etherscan.ApiRunner;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
-import io.goodforgod.api.etherscan.model.TxERC721;
+import io.goodforgod.api.etherscan.model.TxErc721;
 import java.util.List;
 import org.junit.jupiter.api.Test;
 
@@ -14,7 +14,7 @@ class AccountTxRc721TokenTest extends ApiRunner {
 
     @Test
     void correct() {
-        List<TxERC721> txs = getApi().account().txsERC721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67");
+        List<TxErc721> txs = getApi().account().txsErc721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67");
         assertNotNull(txs);
         assertEquals(16, txs.size());
         assertTxs(txs);
@@ -33,7 +33,7 @@ void correct() {
 
     @Test
     void correctStartBlock() {
-        List<TxERC721> txs = getApi().account().txsERC721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4762071);
+        List<TxErc721> txs = getApi().account().txsErc721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4762071);
         System.out.println(txs);
         assertNotNull(txs);
         assertEquals(5, txs.size());
@@ -42,7 +42,7 @@ void correctStartBlock() {
 
     @Test
     void correctStartBlockEndBlock() {
-        List<TxERC721> txs = getApi().account().txsERC721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4761862, 4761934);
+        List<TxErc721> txs = getApi().account().txsErc721("0x1a1ebe0d86f72884c3fd484ae1e796e08f8ffa67", 4761862, 4761934);
         System.out.println(txs);
         assertNotNull(txs);
         assertEquals(11, txs.size());
@@ -52,18 +52,18 @@ void correctStartBlockEndBlock() {
     @Test
     void invalidParamWithError() {
         assertThrows(EtherScanInvalidAddressException.class,
-                () -> getApi().account().txsERC721("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
+                () -> getApi().account().txsErc721("0x6ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7"));
     }
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        List<TxERC721> txs = getApi().account().txsERC721("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
+        List<TxErc721> txs = getApi().account().txsErc721("0x31ec53A8fBa6358d59B3C4476D82cc60A2B0FaD7");
         assertNotNull(txs);
         assertTrue(txs.isEmpty());
     }
 
-    private void assertTxs(List<TxERC721> txs) {
-        for (TxERC721 tx : txs) {
+    private void assertTxs(List<TxErc721> txs) {
+        for (TxErc721 tx : txs) {
             assertNotNull(tx.getBlockHash());
             assertNotNull(tx.getTokenName());
             assertNotNull(tx.getTokenSymbol());

From 34ca1a7f250b7da9a2fa08d0fb3138c3bdc2d812 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 02:38:15 +0300
Subject: [PATCH 19/67] [2.0.0-SNAPSHOT] EthHttpClient contract and package
 refactoring

---
 .../api/etherscan/AccountAPIProvider.java     |  7 ++--
 .../api/etherscan/BasicProvider.java          | 27 +++++++--------
 .../api/etherscan/BlockAPIProvider.java       |  7 ++--
 .../api/etherscan/ContractAPIProvider.java    |  7 ++--
 .../goodforgod/api/etherscan/Converter.java   | 13 ++++++++
 .../api/etherscan/EthScanAPIBuilder.java      | 24 ++++++++++++--
 .../api/etherscan/EtherScanAPI.java           |  5 ++-
 .../api/etherscan/EtherScanAPIProvider.java   | 25 +++++++-------
 .../api/etherscan/GasTrackerAPIProvider.java  |  7 ++--
 .../api/etherscan/LogsAPIProvider.java        |  7 ++--
 .../api/etherscan/ProxyAPIProvider.java       | 11 ++++---
 .../api/etherscan/StatisticAPIProvider.java   | 11 ++++---
 .../api/etherscan/TransactionAPIProvider.java |  7 ++--
 .../{executor => http}/EthHttpClient.java     | 17 ++++++----
 .../impl/UrlEthHttpClient.java                | 32 +++++++++---------
 .../api/etherscan/model/TxErc1155.java        | 19 +++++++++++
 .../api/etherscan/model/TxErc20.java          | 19 +++++++++++
 .../api/etherscan/model/TxErc721.java         | 19 +++++++++++
 .../goodforgod/api/etherscan/model/Wei.java   |  4 +++
 .../api/etherscan/EtherScanAPITests.java      |  6 ++--
 .../gastracker/GasTrackerApiTest.java         | 33 +++++++++++++++++++
 21 files changed, 223 insertions(+), 84 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/Converter.java
 rename src/main/java/io/goodforgod/api/etherscan/{executor => http}/EthHttpClient.java (50%)
 rename src/main/java/io/goodforgod/api/etherscan/{executor => http}/impl/UrlEthHttpClient.java (85%)
 create mode 100644 src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTest.java

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 9382618..1b7bce6 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -2,7 +2,7 @@
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.*;
 import io.goodforgod.api.etherscan.model.response.*;
@@ -49,8 +49,9 @@ final class AccountAPIProvider extends BasicProvider implements AccountAPI {
 
     AccountAPIProvider(RequestQueueManager requestQueueManager,
                        String baseUrl,
-                       EthHttpClient executor) {
-        super(requestQueueManager, "account", baseUrl, executor);
+                       EthHttpClient executor,
+                       Converter converter) {
+        super(requestQueueManager, "account", baseUrl, executor, converter);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index a4ce2a6..f1867d1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -1,15 +1,15 @@
 package io.goodforgod.api.etherscan;
 
-import com.google.gson.Gson;
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanParseException;
 import io.goodforgod.api.etherscan.error.EtherScanRateLimitException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import io.goodforgod.api.etherscan.util.BasicUtils;
-import io.goodforgod.gson.configuration.GsonConfiguration;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
 /**
@@ -30,22 +30,23 @@ abstract class BasicProvider {
     private final String baseUrl;
     private final EthHttpClient executor;
     private final RequestQueueManager queue;
-    private final Gson gson;
+    private final Converter converter;
 
     BasicProvider(RequestQueueManager requestQueueManager,
                   String module,
                   String baseUrl,
-                  EthHttpClient ethHttpClient) {
+                  EthHttpClient ethHttpClient,
+                  Converter converter) {
         this.queue = requestQueueManager;
         this.module = "&module=" + module;
         this.baseUrl = baseUrl;
         this.executor = ethHttpClient;
-        this.gson = new GsonConfiguration().builder().create();
+        this.converter = converter;
     }
 
     <T> T convert(String json, Class<T> tClass) {
         try {
-            final T t = gson.fromJson(json, tClass);
+            final T t = converter.fromJson(json, tClass);
             if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith("Max rate limit reached")) {
                 throw new EtherScanRateLimitException(((StringResponseTO) t).getResult());
             }
@@ -53,7 +54,7 @@ <T> T convert(String json, Class<T> tClass) {
             return t;
         } catch (Exception e) {
             try {
-                final Map<String, Object> map = gson.fromJson(json, Map.class);
+                final Map<String, Object> map = converter.fromJson(json, Map.class);
                 final Object result = map.get("result");
                 if (result instanceof String && ((String) result).startsWith("Max rate limit reached"))
                     throw new EtherScanRateLimitException(((String) result));
@@ -69,18 +70,18 @@ <T> T convert(String json, Class<T> tClass) {
 
     String getRequest(String urlParameters) {
         queue.takeTurn();
-        final String url = baseUrl + module + urlParameters;
-        final String result = executor.get(url);
+        final URI uri = URI.create(baseUrl + module + urlParameters);
+        final String result = executor.get(uri);
         if (BasicUtils.isEmpty(result))
-            throw new EtherScanResponseException("Server returned null value for GET request at URL - " + url);
+            throw new EtherScanResponseException("Server returned null value for GET request at URL - " + uri);
 
         return result;
     }
 
     String postRequest(String urlParameters, String dataToPost) {
         queue.takeTurn();
-        final String url = baseUrl + module + urlParameters;
-        return executor.post(url, dataToPost);
+        final URI uri = URI.create(baseUrl + module + urlParameters);
+        return executor.post(uri, dataToPost.getBytes(StandardCharsets.UTF_8));
     }
 
     <T> T getRequest(String urlParameters, Class<T> tClass) {
diff --git a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
index e5a6d49..98a2d90 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
@@ -1,7 +1,7 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.BlockUncle;
 import io.goodforgod.api.etherscan.model.response.UncleBlockResponseTO;
@@ -24,8 +24,9 @@ final class BlockAPIProvider extends BasicProvider implements BlockAPI {
 
     BlockAPIProvider(RequestQueueManager requestQueueManager,
                      String baseUrl,
-                     EthHttpClient executor) {
-        super(requestQueueManager, "block", baseUrl, executor);
+                     EthHttpClient executor,
+                     Converter converter) {
+        super(requestQueueManager, "block", baseUrl, executor, converter);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index cd96f68..1a8fa9a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -2,7 +2,7 @@
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.Abi;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
@@ -24,8 +24,9 @@ final class ContractAPIProvider extends BasicProvider implements ContractAPI {
 
     ContractAPIProvider(RequestQueueManager requestQueueManager,
                         String baseUrl,
-                        EthHttpClient executor) {
-        super(requestQueueManager, "contract", baseUrl, executor);
+                        EthHttpClient executor,
+                        Converter converter) {
+        super(requestQueueManager, "contract", baseUrl, executor, converter);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/Converter.java b/src/main/java/io/goodforgod/api/etherscan/Converter.java
new file mode 100644
index 0000000..e8c577a
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/Converter.java
@@ -0,0 +1,13 @@
+package io.goodforgod.api.etherscan;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Anton Kurako (GoodforGod)
+ * @since 14.05.2023
+ */
+public interface Converter {
+
+    @NotNull
+    <T> T fromJson(@NotNull String json, @NotNull Class<T> type);
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index 6571121..501bdb1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -1,11 +1,13 @@
 package io.goodforgod.api.etherscan;
 
+import com.google.gson.Gson;
 import io.goodforgod.api.etherscan.error.EtherScanKeyException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
-import io.goodforgod.api.etherscan.executor.impl.UrlEthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
+import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.manager.impl.FakeRequestQueueManager;
 import io.goodforgod.api.etherscan.util.BasicUtils;
+import io.goodforgod.gson.configuration.GsonConfiguration;
 import java.util.function.Supplier;
 import org.jetbrains.annotations.NotNull;
 
@@ -18,10 +20,19 @@ final class EthScanAPIBuilder implements EtherScanAPI.Builder {
     private static final Supplier<EthHttpClient> DEFAULT_SUPPLIER = UrlEthHttpClient::new;
     private static final String DEFAULT_KEY = "YourApiKeyToken";
 
+    private final Gson gson = new GsonConfiguration().builder().create();
+
     private String apiKey = DEFAULT_KEY;
     private EthNetwork ethNetwork = EthNetworks.MAINNET;
     private RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
     private Supplier<EthHttpClient> ethHttpClientSupplier = DEFAULT_SUPPLIER;
+    private Supplier<Converter> converterSupplier = () -> new Converter() {
+
+        @Override
+        public <T> @NotNull T fromJson(@NotNull String json, @NotNull Class<T> type) {
+            return gson.fromJson(json, type);
+        }
+    };
 
     @NotNull
     @Override
@@ -64,8 +75,15 @@ public EtherScanAPI.Builder withHttpClient(@NotNull Supplier<EthHttpClient> http
         return this;
     }
 
+    @NotNull
+    @Override
+    public EtherScanAPI.Builder withConverter(@NotNull Supplier<Converter> converterSupplier) {
+        this.converterSupplier = converterSupplier;
+        return this;
+    }
+
     @Override
     public @NotNull EtherScanAPI build() {
-        return new EtherScanAPIProvider(apiKey, ethNetwork, ethHttpClientSupplier, queueManager);
+        return new EtherScanAPIProvider(apiKey, ethNetwork, queueManager, ethHttpClientSupplier.get(), converterSupplier.get());
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
index d902074..6da3d8f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -1,6 +1,6 @@
 package io.goodforgod.api.etherscan;
 
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import java.util.function.Supplier;
 import org.jetbrains.annotations.NotNull;
@@ -59,6 +59,9 @@ interface Builder {
         @NotNull
         Builder withHttpClient(@NotNull Supplier<EthHttpClient> httpClientSupplier);
 
+        @NotNull
+        Builder withConverter(@NotNull Supplier<Converter> converterSupplier);
+
         @NotNull
         EtherScanAPI build();
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
index 675836f..e698f45 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
@@ -1,8 +1,7 @@
 package io.goodforgod.api.etherscan;
 
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
-import java.util.function.Supplier;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -25,21 +24,21 @@ final class EtherScanAPIProvider implements EtherScanAPI {
 
     EtherScanAPIProvider(String apiKey,
                          EthNetwork network,
-                         Supplier<EthHttpClient> executorSupplier,
-                         RequestQueueManager queue) {
+                         RequestQueueManager queue,
+                         EthHttpClient ethHttpClient,
+                         Converter converter) {
         // EtherScan 1request\5sec limit support by queue manager
-        final EthHttpClient ethHttpClient = executorSupplier.get();
         final String baseUrl = network.domain() + "?apikey=" + apiKey;
 
         this.requestQueueManager = queue;
-        this.account = new AccountAPIProvider(queue, baseUrl, ethHttpClient);
-        this.block = new BlockAPIProvider(queue, baseUrl, ethHttpClient);
-        this.contract = new ContractAPIProvider(queue, baseUrl, ethHttpClient);
-        this.logs = new LogsAPIProvider(queue, baseUrl, ethHttpClient);
-        this.proxy = new ProxyAPIProvider(queue, baseUrl, ethHttpClient);
-        this.stats = new StatisticAPIProvider(queue, baseUrl, ethHttpClient);
-        this.txs = new TransactionAPIProvider(queue, baseUrl, ethHttpClient);
-        this.gasTracker = new GasTrackerAPIProvider(queue, baseUrl, ethHttpClient);
+        this.account = new AccountAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.block = new BlockAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.contract = new ContractAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.logs = new LogsAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.proxy = new ProxyAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.stats = new StatisticAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.txs = new TransactionAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.gasTracker = new GasTrackerAPIProvider(queue, baseUrl, ethHttpClient, converter);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
index d4ec276..a4db5ae 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
@@ -2,7 +2,7 @@
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.GasEstimate;
 import io.goodforgod.api.etherscan.model.GasOracle;
@@ -27,8 +27,9 @@ final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI
 
     GasTrackerAPIProvider(RequestQueueManager queue,
                           String baseUrl,
-                          EthHttpClient ethHttpClient) {
-        super(queue, "gastracker", baseUrl, ethHttpClient);
+                          EthHttpClient ethHttpClient,
+                          Converter converter) {
+        super(queue, "gastracker", baseUrl, ethHttpClient, converter);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
index 771d931..fe9d420 100644
--- a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
@@ -1,7 +1,7 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.Log;
 import io.goodforgod.api.etherscan.model.query.LogQuery;
@@ -24,8 +24,9 @@ final class LogsAPIProvider extends BasicProvider implements LogsAPI {
 
     LogsAPIProvider(RequestQueueManager queue,
                     String baseUrl,
-                    EthHttpClient executor) {
-        super(queue, "logs", baseUrl, executor);
+                    EthHttpClient executor,
+                    Converter converter) {
+        super(queue, "logs", baseUrl, executor, converter);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index 1239294..a306541 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -3,7 +3,7 @@
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidDataHexException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
 import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
@@ -56,10 +56,11 @@ final class ProxyAPIProvider extends BasicProvider implements ProxyAPI {
 
     private static final Pattern EMPTY_HEX = Pattern.compile("0x0+");
 
-    ProxyAPIProvider(final RequestQueueManager queue,
-                     final String baseUrl,
-                     final EthHttpClient executor) {
-        super(queue, "proxy", baseUrl, executor);
+    ProxyAPIProvider(RequestQueueManager queue,
+                     String baseUrl,
+                     EthHttpClient executor,
+                     Converter converter) {
+        super(queue, "proxy", baseUrl, executor, converter);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
index ee4bdaa..1d1bcee 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
@@ -2,7 +2,7 @@
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.Price;
 import io.goodforgod.api.etherscan.model.Supply;
@@ -27,10 +27,11 @@ final class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
 
     private static final String CONTRACT_ADDRESS_PARAM = "&contractaddress=";
 
-    StatisticAPIProvider(final RequestQueueManager queue,
-                         final String baseUrl,
-                         final EthHttpClient executor) {
-        super(queue, "stats", baseUrl, executor);
+    StatisticAPIProvider(RequestQueueManager queue,
+                         String baseUrl,
+                         EthHttpClient executor,
+                         Converter converter) {
+        super(queue, "stats", baseUrl, executor, converter);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
index 91082a8..c131079 100644
--- a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
@@ -1,7 +1,7 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.Status;
 import io.goodforgod.api.etherscan.model.response.ReceiptStatusResponseTO;
@@ -26,8 +26,9 @@ final class TransactionAPIProvider extends BasicProvider implements TransactionA
 
     TransactionAPIProvider(RequestQueueManager queue,
                            String baseUrl,
-                           EthHttpClient executor) {
-        super(queue, "transaction", baseUrl, executor);
+                           EthHttpClient executor,
+                           Converter converter) {
+        super(queue, "transaction", baseUrl, executor, converter);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/executor/EthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
similarity index 50%
rename from src/main/java/io/goodforgod/api/etherscan/executor/EthHttpClient.java
rename to src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
index 4edc507..f4b559d 100644
--- a/src/main/java/io/goodforgod/api/etherscan/executor/EthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
@@ -1,4 +1,7 @@
-package io.goodforgod.api.etherscan.executor;
+package io.goodforgod.api.etherscan.http;
+
+import java.net.URI;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Http Client interface
@@ -11,17 +14,19 @@ public interface EthHttpClient {
     /**
      * Performs a Http GET request
      *
-     * @param url as string
+     * @param uri as string
      * @return result as string
      */
-    String get(String url);
+    @NotNull
+    String get(@NotNull URI uri);
 
     /**
      * Performs a Http POST request
      *
-     * @param url  as string
-     * @param data to post
+     * @param uri  as string
+     * @param body to post
      * @return result as string
      */
-    String post(String url, String data);
+    @NotNull
+    String post(@NotNull URI uri, byte[] body);
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/executor/impl/UrlEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
similarity index 85%
rename from src/main/java/io/goodforgod/api/etherscan/executor/impl/UrlEthHttpClient.java
rename to src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
index ac05125..4178be7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/executor/impl/UrlEthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
@@ -1,17 +1,17 @@
-package io.goodforgod.api.etherscan.executor.impl;
+package io.goodforgod.api.etherscan.http.impl;
 
 import static java.net.HttpURLConnection.*;
 
 import io.goodforgod.api.etherscan.error.EtherScanConnectionException;
 import io.goodforgod.api.etherscan.error.EtherScanTimeoutException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
-import io.goodforgod.api.etherscan.util.BasicUtils;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.SocketTimeoutException;
+import java.net.URI;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
@@ -71,8 +71,8 @@ public UrlEthHttpClient(Duration connectTimeout,
         this.headers = Collections.unmodifiableMap(headers);
     }
 
-    private HttpURLConnection buildConnection(String urlAsString, String method) throws IOException {
-        final URL url = new URL(urlAsString);
+    private HttpURLConnection buildConnection(URI uri, String method) throws IOException {
+        final URL url = uri.toURL();
         final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
         connection.setRequestMethod(method);
         connection.setConnectTimeout(connectTimeout);
@@ -82,12 +82,12 @@ private HttpURLConnection buildConnection(String urlAsString, String method) thr
     }
 
     @Override
-    public String get(final String urlAsString) {
+    public String get(URI uri) {
         try {
-            final HttpURLConnection connection = buildConnection(urlAsString, "GET");
+            final HttpURLConnection connection = buildConnection(uri, "GET");
             final int status = connection.getResponseCode();
             if (status == HTTP_MOVED_TEMP || status == HTTP_MOVED_PERM) {
-                return get(connection.getHeaderField("Location"));
+                return get(URI.create(connection.getHeaderField("Location")));
             } else if ((status >= HTTP_BAD_REQUEST) && (status < HTTP_INTERNAL_ERROR)) {
                 throw new EtherScanConnectionException("Protocol error: " + connection.getResponseMessage());
             } else if (status >= HTTP_INTERNAL_ERROR) {
@@ -105,25 +105,23 @@ public String get(final String urlAsString) {
     }
 
     @Override
-    public String post(String urlAsString, String dataToPost) {
+    public String post(URI uri, byte[] body) {
         try {
-            final HttpURLConnection connection = buildConnection(urlAsString, "POST");
-            final String contentLength = (BasicUtils.isBlank(dataToPost))
-                    ? "0"
-                    : String.valueOf(dataToPost.length());
+            final HttpURLConnection connection = buildConnection(uri, "POST");
+            final int contentLength = body.length;
             connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
-            connection.setRequestProperty("Content-Length", contentLength);
-            connection.setFixedLengthStreamingMode(dataToPost.length());
+            connection.setRequestProperty("Content-Length", String.valueOf(contentLength));
+            connection.setFixedLengthStreamingMode(body.length);
 
             connection.setDoOutput(true);
             connection.connect();
             try (OutputStream os = connection.getOutputStream()) {
-                os.write(dataToPost.getBytes(StandardCharsets.UTF_8));
+                os.write(body);
             }
 
             final int status = connection.getResponseCode();
             if (status == HTTP_MOVED_TEMP || status == HTTP_MOVED_PERM) {
-                return post(connection.getHeaderField("Location"), dataToPost);
+                return post(URI.create(connection.getHeaderField("Location")), body);
             } else if ((status >= HTTP_BAD_REQUEST) && (status < HTTP_INTERNAL_ERROR)) {
                 throw new EtherScanConnectionException("Protocol error: " + connection.getResponseMessage());
             } else if (status >= HTTP_INTERNAL_ERROR) {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
index e57af5f..84e2d40 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -3,6 +3,7 @@
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -63,6 +64,24 @@ public long getConfirmations() {
     }
     // </editor-fold>
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (!(o instanceof TxErc1155))
+            return false;
+        if (!super.equals(o))
+            return false;
+        TxErc1155 txErc1155 = (TxErc1155) o;
+        return Objects.equals(tokenID, txErc1155.tokenID) && Objects.equals(tokenName, txErc1155.tokenName)
+                && Objects.equals(tokenSymbol, txErc1155.tokenSymbol) && Objects.equals(tokenValue, txErc1155.tokenValue);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), tokenID, tokenName, tokenSymbol, tokenValue);
+    }
+
     @Override
     public String toString() {
         return "TxERC721{" +
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index da6f54f..f51b855 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -3,6 +3,7 @@
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -63,6 +64,24 @@ public long getConfirmations() {
     }
     // </editor-fold>
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (!(o instanceof TxErc20))
+            return false;
+        if (!super.equals(o))
+            return false;
+        TxErc20 txErc20 = (TxErc20) o;
+        return Objects.equals(tokenName, txErc20.tokenName) && Objects.equals(tokenSymbol, txErc20.tokenSymbol)
+                && Objects.equals(tokenDecimal, txErc20.tokenDecimal);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), tokenName, tokenSymbol, tokenDecimal);
+    }
+
     @Override
     public String toString() {
         return "TxERC20{" +
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 548113c..8fb2467 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -3,6 +3,7 @@
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -63,6 +64,24 @@ public long getConfirmations() {
     }
     // </editor-fold>
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (!(o instanceof TxErc721))
+            return false;
+        if (!super.equals(o))
+            return false;
+        TxErc721 txErc721 = (TxErc721) o;
+        return Objects.equals(tokenID, txErc721.tokenID) && Objects.equals(tokenName, txErc721.tokenName)
+                && Objects.equals(tokenSymbol, txErc721.tokenSymbol) && Objects.equals(tokenDecimal, txErc721.tokenDecimal);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), tokenID, tokenName, tokenSymbol, tokenDecimal);
+    }
+
     @Override
     public String toString() {
         return "TxERC721{" +
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index 85dd3ab..e863b7a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -11,6 +11,10 @@ public class Wei {
 
     private final BigInteger result;
 
+    public Wei(long value) {
+        this.result = BigInteger.valueOf(value);
+    }
+
     public Wei(BigInteger value) {
         this.result = value;
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
index 5cc0fe7..26865f5 100644
--- a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
@@ -2,8 +2,8 @@
 
 import io.goodforgod.api.etherscan.error.EtherScanKeyException;
 import io.goodforgod.api.etherscan.error.EtherScanTimeoutException;
-import io.goodforgod.api.etherscan.executor.EthHttpClient;
-import io.goodforgod.api.etherscan.executor.impl.UrlEthHttpClient;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
+import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
 import io.goodforgod.api.etherscan.model.Balance;
 import java.time.Duration;
 import java.util.concurrent.TimeUnit;
@@ -17,10 +17,10 @@
 class EtherScanAPITests extends ApiRunner {
 
     private final EthNetworks network = EthNetworks.KOVAN;
-    private final String validKey = "YourKey";
 
     @Test
     void validKey() {
+        String validKey = "YourKey";
         EtherScanAPI api = EtherScanAPI.builder().withApiKey(validKey).withNetwork(network).build();
         assertNotNull(api);
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTest.java b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTest.java
new file mode 100644
index 0000000..ec904a6
--- /dev/null
+++ b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTest.java
@@ -0,0 +1,33 @@
+package io.goodforgod.api.etherscan.gastracker;
+
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.model.GasEstimate;
+import io.goodforgod.api.etherscan.model.GasOracle;
+import io.goodforgod.api.etherscan.model.Wei;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author GoodforGod
+ * @since 14.05.2023
+ */
+class GasTrackerApiTest extends ApiRunner {
+
+    @Test
+    void estimate() {
+        GasEstimate estimate = getApi().gasTracker().estimate(new Wei(123));
+        assertNotNull(estimate);
+        assertNotNull(estimate.getDuration());
+    }
+
+    @Test
+    void oracle() {
+        GasOracle oracle = getApi().gasTracker().oracle();
+        assertNotNull(oracle);
+        assertNotNull(oracle.getGasUsedRatio());
+        assertNotNull(oracle.getFastGasPriceInWei());
+        assertNotNull(oracle.getLastBlock());
+        assertNotNull(oracle.getProposeGasPriceInWei());
+        assertNotNull(oracle.getSafeGasPriceInWei());
+        assertNotNull(oracle.getSuggestBaseFee());
+    }
+}

From f095f0fa4778f5edac65a9f5558812ff4bfd9c9c Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 02:41:55 +0300
Subject: [PATCH 20/67] [2.0.0-SNAPSHOT] Javadoc improved

---
 .../api/etherscan/model/query/LogQuery.java          | 12 ++++++------
 .../etherscan/model/query/LogQueryBuilderImpl.java   |  9 +++++----
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java
index 69e8409..9d8ea5a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQuery.java
@@ -7,7 +7,7 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * Final builded container for The Event Log API
+ * Final built container for The Event Log API
  * EtherScan - API Descriptions <a href="https://etherscan.io/apis#logs">...</a>
  *
  * @see LogQueryBuilderImpl
@@ -21,7 +21,7 @@ public interface LogQuery {
     String params();
 
     @NotNull
-    static Builder builder(String address) {
+    static Builder builder(@NotNull String address) {
         return new LogQueryBuilderImpl(address, MIN_BLOCK, MAX_BLOCK);
     }
 
@@ -34,16 +34,16 @@ interface Builder {
         LogQuery.Builder withBlockTo(long endBlock);
 
         @NotNull
-        LogTopicSingle withTopic(String topic0);
+        LogTopicSingle withTopic(@NotNull String topic0);
 
         @NotNull
-        LogTopicTuple withTopic(String topic0, String topic1);
+        LogTopicTuple withTopic(@NotNull String topic0, @NotNull String topic1);
 
         @NotNull
-        LogTopicTriple withTopic(String topic0, String topic1, String topic2);
+        LogTopicTriple withTopic(@NotNull String topic0, @NotNull String topic1, @NotNull String topic2);
 
         @NotNull
-        LogTopicQuadro withTopic(String topic0, String topic1, String topic2, String topic3);
+        LogTopicQuadro withTopic(@NotNull String topic0, @NotNull String topic1, @NotNull String topic2, @NotNull String topic3);
 
         @NotNull
         LogQuery build();
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
index 0d1eb59..750ab49 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
@@ -37,14 +37,14 @@ final class LogQueryBuilderImpl implements LogQuery.Builder {
     }
 
     @Override
-    public @NotNull LogTopicSingle withTopic(String topic0) {
+    public @NotNull LogTopicSingle withTopic(@NotNull String topic0) {
         if (BasicUtils.isNotHex(topic0))
             throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
         return new LogTopicSingle(address, startBlock, endBlock, topic0);
     }
 
     @Override
-    public @NotNull LogTopicTuple withTopic(String topic0, String topic1) {
+    public @NotNull LogTopicTuple withTopic(@NotNull String topic0, @NotNull String topic1) {
         if (BasicUtils.isNotHex(topic0))
             throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic1))
@@ -53,7 +53,7 @@ final class LogQueryBuilderImpl implements LogQuery.Builder {
     }
 
     @Override
-    public @NotNull LogTopicTriple withTopic(String topic0, String topic1, String topic2) {
+    public @NotNull LogTopicTriple withTopic(@NotNull String topic0, @NotNull String topic1, @NotNull String topic2) {
         if (BasicUtils.isNotHex(topic0))
             throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic1))
@@ -64,7 +64,8 @@ final class LogQueryBuilderImpl implements LogQuery.Builder {
     }
 
     @Override
-    public @NotNull LogTopicQuadro withTopic(String topic0, String topic1, String topic2, String topic3) {
+    public @NotNull LogTopicQuadro
+            withTopic(@NotNull String topic0, @NotNull String topic1, @NotNull String topic2, @NotNull String topic3) {
         if (BasicUtils.isNotHex(topic0))
             throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic1))

From 70cee44655da6e6a7c42e11007eb3f7ef8cb1153 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 02:50:02 +0300
Subject: [PATCH 21/67] [2.0.0-SNAPSHOT] LogQueryBuilderImpl address validation
 added

---
 .../etherscan/manager/impl/SemaphoreRequestQueueManager.java  | 4 ++--
 .../api/etherscan/model/query/LogQueryBuilderImpl.java        | 1 +
 .../java/io/goodforgod/api/etherscan/EtherScanAPITests.java   | 4 ++--
 .../java/io/goodforgod/api/etherscan/logs/LogsApiTest.java    | 4 ++--
 4 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
index ff12cd1..a6e3037 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
@@ -31,8 +31,8 @@ public SemaphoreRequestQueueManager(int size, Duration resetIn, Duration delayIn
     public SemaphoreRequestQueueManager(int size, Duration queueResetTimeIn, Duration delayIn, int initialSize) {
         this.semaphore = new Semaphore(initialSize);
         this.queueResetTimeInMillis = queueResetTimeIn.toMillis();
-        this.executorService.scheduleAtFixedRate(releaseLocks(size + 1), delayIn.toMillis(), queueResetTimeInMillis,
-                TimeUnit.MILLISECONDS);
+        this.executorService.scheduleAtFixedRate(releaseLocks(size + 1),
+                delayIn.toMillis(), queueResetTimeInMillis, TimeUnit.MILLISECONDS);
     }
 
     @SuppressWarnings("java:S899")
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
index 750ab49..716cfa4 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
@@ -21,6 +21,7 @@ final class LogQueryBuilderImpl implements LogQuery.Builder {
     private final long startBlock, endBlock;
 
     LogQueryBuilderImpl(String address, long startBlock, long endBlock) {
+        BasicUtils.validateAddress(address);
         this.address = address;
         this.startBlock = startBlock;
         this.endBlock = endBlock;
diff --git a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
index 26865f5..22c58d6 100644
--- a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
@@ -1,7 +1,7 @@
 package io.goodforgod.api.etherscan;
 
+import io.goodforgod.api.etherscan.error.EtherScanConnectionException;
 import io.goodforgod.api.etherscan.error.EtherScanKeyException;
-import io.goodforgod.api.etherscan.error.EtherScanTimeoutException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
 import io.goodforgod.api.etherscan.model.Balance;
@@ -70,7 +70,7 @@ void timeout() throws InterruptedException {
         Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300), Duration.ofMillis(300));
         EtherScanAPI api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.KOVAN).withHttpClient(supplier)
                 .build();
-        assertThrows(EtherScanTimeoutException.class,
+        assertThrows(EtherScanConnectionException.class,
                 () -> api.account().blocksMined("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D"));
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java b/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
index 0f90d37..7d9fe64 100644
--- a/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
@@ -38,10 +38,10 @@ static Stream<Arguments> source() {
                 .build();
 
         return Stream.of(
-                Arguments.of(single, 423),
+                Arguments.of(single, 424),
                 Arguments.of(singleInvalidAddr, 0),
                 Arguments.of(tupleAnd, 1),
-                Arguments.of(tupleOr, 425));
+                Arguments.of(tupleOr, 426));
     }
 
     @ParameterizedTest

From 43a0693922d071aed0dd46d741854755873b6bfd Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 02:57:19 +0300
Subject: [PATCH 22/67] [2.0.0-SNAPSHOT] CI Report only for Java 17 (avoid rate
 limiter)

---
 .github/workflows/gradle.yml                             | 1 +
 src/test/java/io/goodforgod/api/etherscan/ApiRunner.java | 9 ++-------
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index e4c7620..b4c0bb4 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -37,6 +37,7 @@ jobs:
           API_KEY: ${{ secrets.API_KEY }}
 
       - name: SonarQube
+        if: matrix.java == '17'
         run: ./gradlew sonarqube
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index cd4a657..cd8c7d1 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -1,8 +1,6 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
-import io.goodforgod.api.etherscan.manager.impl.SemaphoreRequestQueueManager;
-import java.time.Duration;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 
@@ -18,14 +16,11 @@ public class ApiRunner extends Assertions {
 
     static {
         final String key = System.getenv("API_KEY");
+        final RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
+
         apiKey = (key == null || key.isEmpty())
                 ? DEFAULT_KEY
                 : key;
-
-        final RequestQueueManager queueManager = (DEFAULT_KEY.equals(apiKey))
-                ? RequestQueueManager.DEFAULT
-                : new SemaphoreRequestQueueManager(1, Duration.ofMillis(1200L), Duration.ofMillis(1200L), 0);
-
         api = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
                 .build();
         apiKovan = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.KOVAN).withQueue(queueManager)

From 9b366c3b58dc6470b841a9b2b91c21291f2ebc48 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 03:07:14 +0300
Subject: [PATCH 23/67] [2.0.0-SNAPSHOT] EthNetworks cleanup

---
 .../goodforgod/api/etherscan/EthNetworks.java |  5 +---
 .../goodforgod/api/etherscan/ApiRunner.java   | 24 -------------------
 2 files changed, 1 insertion(+), 28 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/EthNetworks.java b/src/main/java/io/goodforgod/api/etherscan/EthNetworks.java
index 4dbe138..9e18508 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthNetworks.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthNetworks.java
@@ -10,11 +10,8 @@
 public enum EthNetworks implements EthNetwork {
 
     MAINNET("api", "io"),
-    ROPSTEN("api-ropsten", "io"),
-    KOVAN("api-kovan", "io"),
-    TOBALABA("api-tobalaba", "com"),
     GORLI("api-goerli", "io"),
-    RINKEBY("api-rinkeby", "io");
+    SEPOLIA("api-sepolia", "io");
 
     private final URI domain;
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index cd8c7d1..7a5ef52 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -9,9 +9,6 @@ public class ApiRunner extends Assertions {
     private static final String DEFAULT_KEY = "YourApiKeyToken";
 
     private static final EtherScanAPI api;
-    private static final EtherScanAPI apiRopsten;
-    private static final EtherScanAPI apiRinkeby;
-    private static final EtherScanAPI apiKovan;
     private static final String apiKey;
 
     static {
@@ -23,12 +20,6 @@ public class ApiRunner extends Assertions {
                 : key;
         api = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
                 .build();
-        apiKovan = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.KOVAN).withQueue(queueManager)
-                .build();
-        apiRopsten = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.ROPSTEN).withQueue(queueManager)
-                .build();
-        apiRinkeby = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.RINKEBY).withQueue(queueManager)
-                .build();
     }
 
     public static String getApiKey() {
@@ -39,23 +30,8 @@ public static EtherScanAPI getApi() {
         return api;
     }
 
-    public static EtherScanAPI getApiRopsten() {
-        return apiRopsten;
-    }
-
-    public static EtherScanAPI getApiRinkeby() {
-        return apiRinkeby;
-    }
-
-    public static EtherScanAPI getApiKovan() {
-        return apiKovan;
-    }
-
     @AfterAll
     public static void cleanup() throws Exception {
         api.close();
-        apiRopsten.close();
-        apiRinkeby.close();
-        apiKovan.close();
     }
 }

From bf9f02bad2328a37859fe52f4e58b95b210c0d76 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 03:29:43 +0300
Subject: [PATCH 24/67] [2.0.0-SNAPSHOT] SemaphoreRequestQueueManager improved

---
 .github/workflows/gradle.yml                  |  9 +++++-
 .../manager/RequestQueueManager.java          |  7 ++--
 .../impl/SemaphoreRequestQueueManager.java    | 24 +++++++-------
 .../goodforgod/api/etherscan/ApiRunner.java   | 32 ++++++++++++-------
 .../api/etherscan/EtherScanAPITests.java      | 11 ++++---
 ...Test.java => AccountBalanceListTests.java} |  2 +-
 ...anceTest.java => AccountBalanceTests.java} |  2 +-
 ...Test.java => AccountMinedBlocksTests.java} |  2 +-
 ...est.java => AccountTokenBalanceTests.java} |  2 +-
 ...rc20Test.java => AccountTxErc20Tests.java} |  2 +-
 ...java => AccountTxInternalByHashTests.java} |  2 +-
 ...lTest.java => AccountTxInternalTests.java} |  2 +-
 ...st.java => AccountTxRc1155TokenTests.java} |  2 +-
 ...est.java => AccountTxRc721TokenTests.java} |  2 +-
 ...countTxsTest.java => AccountTxsTests.java} |  2 +-
 .../{BlockApiTest.java => BlockApiTests.java} |  2 +-
 ...ractApiTest.java => ContractApiTests.java} |  2 +-
 ...erApiTest.java => GasTrackerApiTests.java} |  2 +-
 ...derTest.java => LogQueryBuilderTests.java} |  2 +-
 .../{LogsApiTest.java => LogsApiTests.java}   |  2 +-
 ...=> SemaphoreRequestQueueManagerTests.java} | 15 ++-------
 .../etherscan/model/ModelBuilderTests.java    |  7 ++++
 ...ckApiTest.java => ProxyBlockApiTests.java} |  4 +--
 ...est.java => ProxyBlockLastNoApiTests.java} |  2 +-
 ...Test.java => ProxyBlockUncleApiTests.java} |  2 +-
 ...allApiTest.java => ProxyCallApiTests.java} |  2 +-
 ...odeApiTest.java => ProxyCodeApiTests.java} |  2 +-
 ...yGasApiTest.java => ProxyGasApiTests.java} |  2 +-
 ...ApiTest.java => ProxyStorageApiTests.java} |  2 +-
 ...oxyTxApiTest.java => ProxyTxApiTests.java} |  2 +-
 ...ApiTest.java => ProxyTxCountApiTests.java} |  2 +-
 ...iTest.java => ProxyTxReceiptApiTests.java} |  2 +-
 ...iTest.java => ProxyTxSendRawApiTests.java} |  2 +-
 ...iTest.java => StatisticPriceApiTests.java} |  2 +-
 ...Test.java => StatisticSupplyApiTests.java} |  2 +-
 ...java => StatisticTokenSupplyApiTests.java} |  2 +-
 ...Test.java => TransactionExecApiTests.java} |  2 +-
 ...t.java => TransactionReceiptApiTests.java} |  2 +-
 38 files changed, 89 insertions(+), 80 deletions(-)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountBalanceListTest.java => AccountBalanceListTests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountBalanceTest.java => AccountBalanceTests.java} (96%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountMinedBlocksTest.java => AccountMinedBlocksTests.java} (96%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTokenBalanceTest.java => AccountTokenBalanceTests.java} (97%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTxErc20Test.java => AccountTxErc20Tests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTxInternalByHashTest.java => AccountTxInternalByHashTests.java} (97%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTxInternalTest.java => AccountTxInternalTests.java} (97%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTxRc1155TokenTest.java => AccountTxRc1155TokenTests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTxRc721TokenTest.java => AccountTxRc721TokenTests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/account/{AccountTxsTest.java => AccountTxsTests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/block/{BlockApiTest.java => BlockApiTests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/contract/{ContractApiTest.java => ContractApiTests.java} (96%)
 rename src/test/java/io/goodforgod/api/etherscan/gastracker/{GasTrackerApiTest.java => GasTrackerApiTests.java} (95%)
 rename src/test/java/io/goodforgod/api/etherscan/logs/{LogQueryBuilderTest.java => LogQueryBuilderTests.java} (99%)
 rename src/test/java/io/goodforgod/api/etherscan/logs/{LogsApiTest.java => LogsApiTests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/manager/{SemaphoreRequestQueueManagerTest.java => SemaphoreRequestQueueManagerTests.java} (70%)
 create mode 100644 src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyBlockApiTest.java => ProxyBlockApiTests.java} (97%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyBlockLastNoApiTest.java => ProxyBlockLastNoApiTests.java} (85%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyBlockUncleApiTest.java => ProxyBlockUncleApiTests.java} (94%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyCallApiTest.java => ProxyCallApiTests.java} (97%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyCodeApiTest.java => ProxyCodeApiTests.java} (95%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyGasApiTest.java => ProxyGasApiTests.java} (96%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyStorageApiTest.java => ProxyStorageApiTests.java} (95%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyTxApiTest.java => ProxyTxApiTests.java} (98%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyTxCountApiTest.java => ProxyTxCountApiTests.java} (96%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyTxReceiptApiTest.java => ProxyTxReceiptApiTests.java} (97%)
 rename src/test/java/io/goodforgod/api/etherscan/proxy/{ProxyTxSendRawApiTest.java => ProxyTxSendRawApiTests.java} (95%)
 rename src/test/java/io/goodforgod/api/etherscan/statistic/{StatisticPriceApiTest.java => StatisticPriceApiTests.java} (93%)
 rename src/test/java/io/goodforgod/api/etherscan/statistic/{StatisticSupplyApiTest.java => StatisticSupplyApiTests.java} (93%)
 rename src/test/java/io/goodforgod/api/etherscan/statistic/{StatisticTokenSupplyApiTest.java => StatisticTokenSupplyApiTests.java} (94%)
 rename src/test/java/io/goodforgod/api/etherscan/transaction/{TransactionExecApiTest.java => TransactionExecApiTests.java} (96%)
 rename src/test/java/io/goodforgod/api/etherscan/transaction/{TransactionReceiptApiTest.java => TransactionReceiptApiTests.java} (95%)

diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index b4c0bb4..3eb55f0 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -32,9 +32,16 @@ jobs:
         run: ./gradlew spotlessCheck
 
       - name: Test
+        if: matrix.java == '11'
         run: ./gradlew test jacocoTestReport
         env:
-          API_KEY: ${{ secrets.API_KEY }}
+          API_KEY: ${{ secrets.ETHERSCAN_API_KEY_1 }}
+
+      - name: Test
+        if: matrix.java == '17'
+        run: ./gradlew test jacocoTestReport
+        env:
+          API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
 
       - name: SonarQube
         if: matrix.java == '17'
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index d568601..6b2740a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -12,11 +12,8 @@
  */
 public interface RequestQueueManager extends AutoCloseable {
 
-    RequestQueueManager DEFAULT = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5050L),
-            Duration.ofMillis(5050L), 0);
-
-    RequestQueueManager PERSONAL = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1050L),
-            Duration.ofMillis(1050L), 5);
+    RequestQueueManager DEFAULT = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5005L));
+    RequestQueueManager PERSONAL = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1005L));
 
     /**
      * Waits in queue for chance to take turn
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
index a6e3037..2a3483c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
@@ -21,18 +21,10 @@ public final class SemaphoreRequestQueueManager implements RequestQueueManager,
     private final long queueResetTimeInMillis;
 
     public SemaphoreRequestQueueManager(int size, Duration resetIn) {
-        this(size, resetIn, resetIn);
-    }
-
-    public SemaphoreRequestQueueManager(int size, Duration resetIn, Duration delayIn) {
-        this(size, resetIn, delayIn, size);
-    }
-
-    public SemaphoreRequestQueueManager(int size, Duration queueResetTimeIn, Duration delayIn, int initialSize) {
-        this.semaphore = new Semaphore(initialSize);
-        this.queueResetTimeInMillis = queueResetTimeIn.toMillis();
-        this.executorService.scheduleAtFixedRate(releaseLocks(size + 1),
-                delayIn.toMillis(), queueResetTimeInMillis, TimeUnit.MILLISECONDS);
+        this.semaphore = new Semaphore(0);
+        this.queueResetTimeInMillis = resetIn.toMillis();
+        this.executorService.scheduleAtFixedRate(releaseLocks(size),
+                resetIn.toMillis(), queueResetTimeInMillis, TimeUnit.MILLISECONDS);
     }
 
     @SuppressWarnings("java:S899")
@@ -46,7 +38,13 @@ public void takeTurn() {
     }
 
     private Runnable releaseLocks(int toRelease) {
-        return () -> semaphore.release(toRelease);
+        return () -> {
+            int availablePermits = semaphore.availablePermits();
+            int neededPermits = toRelease - availablePermits;
+            if (neededPermits > 0) {
+                semaphore.release(neededPermits);
+            }
+        };
     }
 
     @Override
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index 7a5ef52..d63bc73 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import java.util.Map;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 
@@ -8,30 +9,37 @@ public class ApiRunner extends Assertions {
 
     private static final String DEFAULT_KEY = "YourApiKeyToken";
 
-    private static final EtherScanAPI api;
-    private static final String apiKey;
+    private static final String API_KEY;
+    private static final EtherScanAPI API;
 
     static {
-        final String key = System.getenv("API_KEY");
-        final RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
-
-        apiKey = (key == null || key.isEmpty())
-                ? DEFAULT_KEY
-                : key;
-        api = EtherScanAPI.builder().withApiKey(ApiRunner.apiKey).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
+        API_KEY = System.getenv().entrySet().stream()
+                .filter(e -> e.getKey().startsWith("ETHERSCAN_API_KEY"))
+                .map(Map.Entry::getValue)
+                .findFirst()
+                .orElse(DEFAULT_KEY);
+
+        final RequestQueueManager queueManager = (DEFAULT_KEY.equals(API_KEY))
+                ? RequestQueueManager.DEFAULT
+                : RequestQueueManager.PERSONAL;
+
+        API = EtherScanAPI.builder()
+                .withApiKey(ApiRunner.API_KEY)
+                .withNetwork(EthNetworks.MAINNET)
+                .withQueue(queueManager)
                 .build();
     }
 
     public static String getApiKey() {
-        return apiKey;
+        return API_KEY;
     }
 
     public static EtherScanAPI getApi() {
-        return api;
+        return API;
     }
 
     @AfterAll
     public static void cleanup() throws Exception {
-        api.close();
+        API.close();
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
index 22c58d6..c50b03a 100644
--- a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
@@ -5,6 +5,7 @@
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
 import io.goodforgod.api.etherscan.model.Balance;
+import java.net.URI;
 import java.time.Duration;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
@@ -16,7 +17,7 @@
  */
 class EtherScanAPITests extends ApiRunner {
 
-    private final EthNetworks network = EthNetworks.KOVAN;
+    private final EthNetworks network = EthNetworks.SEPOLIA;
 
     @Test
     void validKey() {
@@ -46,14 +47,12 @@ void noTimeoutOnRead() {
 
     @Test
     void noTimeoutOnReadGroli() {
-        Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300));
         Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
         assertNotNull(balance);
     }
 
     @Test
     void noTimeoutOnReadTobalala() {
-        Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(30000));
         Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
         assertNotNull(balance);
     }
@@ -68,8 +67,12 @@ void noTimeoutUnlimitedAwait() {
     void timeout() throws InterruptedException {
         TimeUnit.SECONDS.sleep(5);
         Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300), Duration.ofMillis(300));
-        EtherScanAPI api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.KOVAN).withHttpClient(supplier)
+        EtherScanAPI api = EtherScanAPI.builder()
+                .withApiKey(getApiKey())
+                .withNetwork(() -> URI.create("https://api-unknown.etherscan.io/api"))
+                .withHttpClient(supplier)
                 .build();
+
         assertThrows(EtherScanConnectionException.class,
                 () -> api.account().blocksMined("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D"));
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTests.java
index cd3dac9..f611b62 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTests.java
@@ -13,7 +13,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountBalanceListTest extends ApiRunner {
+class AccountBalanceListTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTests.java
similarity index 96%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTests.java
index 4c06c7c..f22a724 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountBalanceTest extends ApiRunner {
+class AccountBalanceTests extends ApiRunner {
 
     private final EtherScanAPI api = getApi();
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTests.java
similarity index 96%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTests.java
index 13d5075..3e19e96 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountMinedBlocksTests.java
@@ -11,7 +11,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountMinedBlocksTest extends ApiRunner {
+class AccountMinedBlocksTests extends ApiRunner {
 
     private final EtherScanAPI api = getApi();
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTests.java
similarity index 97%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTests.java
index 4df75f3..4a7d921 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountTokenBalanceTest extends ApiRunner {
+class AccountTokenBalanceTests extends ApiRunner {
 
     private final EtherScanAPI api = getApi();
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Test.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Test.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
index 0a94289..928b2e3 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Test.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountTxErc20Test extends ApiRunner {
+class AccountTxErc20Tests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTests.java
similarity index 97%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTests.java
index 13036bc..eb06b60 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalByHashTests.java
@@ -12,7 +12,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountTxInternalByHashTest extends ApiRunner {
+class AccountTxInternalByHashTests extends ApiRunner {
 
     private final EtherScanAPI api = getApi();
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTests.java
similarity index 97%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTests.java
index 6fb92b4..1d4220d 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxInternalTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountTxInternalTest extends ApiRunner {
+class AccountTxInternalTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
index ce3a680..0430dc8 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 14.05.2023
  */
-class AccountTxRc1155TokenTest extends ApiRunner {
+class AccountTxRc1155TokenTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
index b7988db..9a5a322 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
@@ -10,7 +10,7 @@
  * @author NGuggs
  * @since 11.28.2021
  */
-class AccountTxRc721TokenTest extends ApiRunner {
+class AccountTxRc721TokenTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTest.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTest.java
rename to src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
index a2cffd1..3ee8ad1 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class AccountTxsTest extends ApiRunner {
+class AccountTxsTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTest.java b/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/block/BlockApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/block/BlockApiTests.java
index 8e3b529..3e84ab7 100644
--- a/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class BlockApiTest extends ApiRunner {
+class BlockApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTest.java b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
similarity index 96%
rename from src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
index 62aa7da..4fd0fdb 100644
--- a/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ContractApiTest extends ApiRunner {
+class ContractApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTest.java b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
similarity index 95%
rename from src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
index ec904a6..1d92eb4 100644
--- a/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 14.05.2023
  */
-class GasTrackerApiTest extends ApiRunner {
+class GasTrackerApiTests extends ApiRunner {
 
     @Test
     void estimate() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTest.java b/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTests.java
similarity index 99%
rename from src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTest.java
rename to src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTests.java
index 752c34c..339f07e 100644
--- a/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class LogQueryBuilderTest extends ApiRunner {
+class LogQueryBuilderTests extends ApiRunner {
 
     @Test
     void singleCorrect() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java b/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTests.java
index 7d9fe64..0197c5f 100644
--- a/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/logs/LogsApiTests.java
@@ -14,7 +14,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class LogsApiTest extends ApiRunner {
+class LogsApiTests extends ApiRunner {
 
     static Stream<Arguments> source() {
         LogQuery single = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
diff --git a/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java b/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTests.java
similarity index 70%
rename from src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
rename to src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTests.java
index 0d6daf6..183c442 100644
--- a/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/manager/SemaphoreRequestQueueManagerTests.java
@@ -11,7 +11,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class SemaphoreRequestQueueManagerTest extends ApiRunner {
+class SemaphoreRequestQueueManagerTests extends ApiRunner {
 
     @Test
     void fakeManager() {
@@ -37,20 +37,9 @@ void queueManager() {
     @Test
     @Timeout(4500)
     void queueManagerWithDelay() {
-        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(2),
-                Duration.ofSeconds(2));
+        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(2));
         requestQueueManager.takeTurn();
         requestQueueManager.takeTurn();
         assertNotNull(requestQueueManager);
     }
-
-    @Test
-    void queueManagerTimeout() {
-        RequestQueueManager requestQueueManager = new SemaphoreRequestQueueManager(1, Duration.ofSeconds(3));
-        requestQueueManager.takeTurn();
-        long start = System.currentTimeMillis();
-        requestQueueManager.takeTurn();
-        long end = System.currentTimeMillis();
-        assertEquals(3, Math.round((double) (end - start) / 1000));
-    }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
new file mode 100644
index 0000000..6f5fc22
--- /dev/null
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -0,0 +1,7 @@
+package io.goodforgod.api.etherscan.model;
+
+/**
+ * @author Anton Kurako (GoodforGod)
+ * @since 14.05.2023
+ */
+class ModelBuilderTests {}
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
similarity index 97%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
index e31aab8..44d786d 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
@@ -12,11 +12,11 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyBlockApiTest extends ApiRunner {
+class ProxyBlockApiTests extends ApiRunner {
 
     private final EtherScanAPI api;
 
-    ProxyBlockApiTest() {
+    ProxyBlockApiTests() {
         final RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
         this.api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
                 .build();
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTests.java
similarity index 85%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTests.java
index c4f5e31..568d9ae 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockLastNoApiTests.java
@@ -7,7 +7,7 @@
  * @author GoodforGod
  * @since 13.11.2018
  */
-class ProxyBlockLastNoApiTest extends ApiRunner {
+class ProxyBlockLastNoApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTests.java
similarity index 94%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTests.java
index c575072..01725c5 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockUncleApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 13.11.2018
  */
-class ProxyBlockUncleApiTest extends ApiRunner {
+class ProxyBlockUncleApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTests.java
similarity index 97%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTests.java
index 67e7682..d5168c6 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCallApiTests.java
@@ -11,7 +11,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyCallApiTest extends ApiRunner {
+class ProxyCallApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTests.java
similarity index 95%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTests.java
index c9dab25..1e3c696 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyCodeApiTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyCodeApiTest extends ApiRunner {
+class ProxyCodeApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTests.java
similarity index 96%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTests.java
index 1b40705..0ab2a77 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyGasApiTest extends ApiRunner {
+class ProxyGasApiTests extends ApiRunner {
 
     @Test
     void correctPrice() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTests.java
similarity index 95%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTests.java
index 2580e22..3c6d221 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyStorageApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyStorageApiTest extends ApiRunner {
+class ProxyStorageApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTests.java
similarity index 98%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTests.java
index d6790bd..6c7dbb7 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyTxApiTest extends ApiRunner {
+class ProxyTxApiTests extends ApiRunner {
 
     @Test
     void correctByHash() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTests.java
similarity index 96%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTests.java
index a2327da..95ed859 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxCountApiTests.java
@@ -8,7 +8,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyTxCountApiTest extends ApiRunner {
+class ProxyTxCountApiTests extends ApiRunner {
 
     @Test
     void correctSended() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
similarity index 97%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
index ba6370c..7a6624c 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class ProxyTxReceiptApiTest extends ApiRunner {
+class ProxyTxReceiptApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTest.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTests.java
similarity index 95%
rename from src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTests.java
index 9f69060..3910bf8 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxSendRawApiTests.java
@@ -11,7 +11,7 @@
  * @since 03.11.2018
  */
 // TODO contact etherscan and ask about method behavior
-class ProxyTxSendRawApiTest extends ApiRunner {
+class ProxyTxSendRawApiTests extends ApiRunner {
 
     void correct() {
         Optional<String> sendRaw = getApi().proxy()
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTest.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
similarity index 93%
rename from src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
index eb43b6e..37e0ec0 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
@@ -8,7 +8,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class StatisticPriceApiTest extends ApiRunner {
+class StatisticPriceApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTest.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
similarity index 93%
rename from src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
index c1e8e58..fa79028 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class StatisticSupplyApiTest extends ApiRunner {
+class StatisticSupplyApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTest.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
similarity index 94%
rename from src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
index 84c086a..07f8eca 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class StatisticTokenSupplyApiTest extends ApiRunner {
+class StatisticTokenSupplyApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTest.java b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTests.java
similarity index 96%
rename from src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTests.java
index a2a5860..eb595c3 100644
--- a/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTests.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class TransactionExecApiTest extends ApiRunner {
+class TransactionExecApiTests extends ApiRunner {
 
     @Test
     void correct() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTest.java b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTests.java
similarity index 95%
rename from src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTest.java
rename to src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTests.java
index 83ca5af..8ff0817 100644
--- a/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTest.java
+++ b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionReceiptApiTests.java
@@ -9,7 +9,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-class TransactionReceiptApiTest extends ApiRunner {
+class TransactionReceiptApiTests extends ApiRunner {
 
     @Test
     void correct() {

From 55788d505b74d71978001d9fae8f929b0a7ec8ab Mon Sep 17 00:00:00 2001
From: guggio <sebastian.guggisberg@gmail.com>
Date: Sun, 17 Jul 2022 12:10:23 +0300
Subject: [PATCH 25/67] [2.0.0-SNAPSHOT] Refactoring of token transfers -
 Inclusion of tokenID in Erc721 transfers - Support for Erc1155 transfers

(cherry picked from commit ca4b7d5eca7d9d08688af3e38c6702f77c149d2d)
---
 .../io/api/etherscan/model/BaseTxToken.java   | 59 +++++++++++++++++++
 .../io/api/etherscan/model/TxErc1155.java     | 25 ++++++++
 .../java/io/api/etherscan/model/TxErc20.java  | 19 ++++++
 .../java/io/api/etherscan/model/TxErc721.java | 25 ++++++++
 .../model/response/TxErc1155ResponseTO.java   | 11 ----
 .../model/response/TxErc20ResponseTO.java     | 11 ----
 .../model/response/TxErc721ResponseTO.java    | 11 ----
 7 files changed, 128 insertions(+), 33 deletions(-)
 create mode 100644 src/main/java/io/api/etherscan/model/BaseTxToken.java
 create mode 100644 src/main/java/io/api/etherscan/model/TxErc1155.java
 create mode 100644 src/main/java/io/api/etherscan/model/TxErc20.java
 create mode 100644 src/main/java/io/api/etherscan/model/TxErc721.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java

diff --git a/src/main/java/io/api/etherscan/model/BaseTxToken.java b/src/main/java/io/api/etherscan/model/BaseTxToken.java
new file mode 100644
index 0000000..e1965ce
--- /dev/null
+++ b/src/main/java/io/api/etherscan/model/BaseTxToken.java
@@ -0,0 +1,59 @@
+package io.api.etherscan.model;
+
+public abstract class BaseTxToken extends BaseTx {
+
+    private long nonce;
+    private String blockHash;
+    private String tokenName;
+    private String tokenSymbol;
+    private int transactionIndex;
+    private long gasPrice;
+    private long cumulativeGasUsed;
+    private long confirmations;
+
+    public long getNonce() {
+        return nonce;
+    }
+
+    public String getBlockHash() {
+        return blockHash;
+    }
+
+    public String getTokenName() {
+        return tokenName;
+    }
+
+    public String getTokenSymbol() {
+        return tokenSymbol;
+    }
+
+    public int getTransactionIndex() {
+        return transactionIndex;
+    }
+
+    public long getGasPrice() {
+        return gasPrice;
+    }
+
+    public long getCumulativeGasUsed() {
+        return cumulativeGasUsed;
+    }
+
+    public long getConfirmations() {
+        return confirmations;
+    }
+
+    @Override
+    public String toString() {
+        return "BaseTxToken{" +
+                "nonce=" + nonce +
+                ", blockHash='" + blockHash + '\'' +
+                ", tokenName='" + tokenName + '\'' +
+                ", tokenSymbol='" + tokenSymbol + '\'' +
+                ", transactionIndex=" + transactionIndex +
+                ", gasPrice=" + gasPrice +
+                ", cumulativeGasUsed=" + cumulativeGasUsed +
+                ", confirmations=" + confirmations +
+                '}' + super.toString();
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/TxErc1155.java b/src/main/java/io/api/etherscan/model/TxErc1155.java
new file mode 100644
index 0000000..b926b1b
--- /dev/null
+++ b/src/main/java/io/api/etherscan/model/TxErc1155.java
@@ -0,0 +1,25 @@
+package io.api.etherscan.model;
+
+import java.math.BigInteger;
+
+public class TxErc1155 extends BaseTxToken {
+
+    private BigInteger tokenID;
+    private BigInteger tokenValue;
+
+    public BigInteger getTokenID() {
+        return tokenID;
+    }
+
+    public BigInteger getTokenValue() {
+        return tokenValue;
+    }
+
+    @Override
+    public String toString() {
+        return "TxErc1155{" +
+                "tokenID=" + tokenID +
+                ", tokenValue=" + tokenValue +
+                '}' + super.toString();
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/TxErc20.java b/src/main/java/io/api/etherscan/model/TxErc20.java
new file mode 100644
index 0000000..9c4e65e
--- /dev/null
+++ b/src/main/java/io/api/etherscan/model/TxErc20.java
@@ -0,0 +1,19 @@
+package io.api.etherscan.model;
+
+import java.math.BigInteger;
+
+public class TxErc20 extends BaseTxToken {
+
+    private BigInteger tokenDecimal;
+
+    public BigInteger getTokenDecimal() {
+        return tokenDecimal;
+    }
+
+    @Override
+    public String toString() {
+        return "TxErc20{" +
+                "tokenDecimal=" + tokenDecimal +
+                '}' + super.toString();
+    }
+}
diff --git a/src/main/java/io/api/etherscan/model/TxErc721.java b/src/main/java/io/api/etherscan/model/TxErc721.java
new file mode 100644
index 0000000..9f70c3d
--- /dev/null
+++ b/src/main/java/io/api/etherscan/model/TxErc721.java
@@ -0,0 +1,25 @@
+package io.api.etherscan.model;
+
+import java.math.BigInteger;
+
+public class TxErc721 extends BaseTxToken {
+
+    private BigInteger tokenID;
+    private BigInteger tokenDecimal;
+
+    public BigInteger getTokenID() {
+        return tokenID;
+    }
+
+    public BigInteger getTokenDecimal() {
+        return tokenDecimal;
+    }
+
+    @Override
+    public String toString() {
+        return "TxErc721{" +
+                "tokenID=" + tokenID +
+                ", tokenDecimal=" + tokenDecimal +
+                '}' + super.toString();
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
deleted file mode 100644
index 994d2cd..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.goodforgod.api.etherscan.model.response;
-
-import io.goodforgod.api.etherscan.model.TxErc1155;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class TxErc1155ResponseTO extends BaseListResponseTO<TxErc1155> {
-
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
deleted file mode 100644
index d5d3f6e..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.goodforgod.api.etherscan.model.response;
-
-import io.goodforgod.api.etherscan.model.TxErc20;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class TxErc20ResponseTO extends BaseListResponseTO<TxErc20> {
-
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java
deleted file mode 100644
index 2a9403f..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.goodforgod.api.etherscan.model.response;
-
-import io.goodforgod.api.etherscan.model.TxErc721;
-
-/**
- * @author GoodforGod
- * @since 29.10.2018
- */
-public class TxErc721ResponseTO extends BaseListResponseTO<TxErc721> {
-
-}

From 8ec7d9349b6cbb07b97d21174216dea87a2111f4 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 03:33:45 +0300
Subject: [PATCH 26/67] [2.0.0-SNAPSHOT] Refactoring of token transfers -
 Inclusion of tokenID in Erc721 transfers - Support for Erc1155 transfers

(cherry picked from commit ca4b7d5eca7d9d08688af3e38c6702f77c149d2d)
---
 .../io/api/etherscan/model/BaseTxToken.java   | 59 -------------------
 .../io/api/etherscan/model/TxErc1155.java     | 25 --------
 .../java/io/api/etherscan/model/TxErc20.java  | 19 ------
 .../java/io/api/etherscan/model/TxErc721.java | 25 --------
 4 files changed, 128 deletions(-)
 delete mode 100644 src/main/java/io/api/etherscan/model/BaseTxToken.java
 delete mode 100644 src/main/java/io/api/etherscan/model/TxErc1155.java
 delete mode 100644 src/main/java/io/api/etherscan/model/TxErc20.java
 delete mode 100644 src/main/java/io/api/etherscan/model/TxErc721.java

diff --git a/src/main/java/io/api/etherscan/model/BaseTxToken.java b/src/main/java/io/api/etherscan/model/BaseTxToken.java
deleted file mode 100644
index e1965ce..0000000
--- a/src/main/java/io/api/etherscan/model/BaseTxToken.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package io.api.etherscan.model;
-
-public abstract class BaseTxToken extends BaseTx {
-
-    private long nonce;
-    private String blockHash;
-    private String tokenName;
-    private String tokenSymbol;
-    private int transactionIndex;
-    private long gasPrice;
-    private long cumulativeGasUsed;
-    private long confirmations;
-
-    public long getNonce() {
-        return nonce;
-    }
-
-    public String getBlockHash() {
-        return blockHash;
-    }
-
-    public String getTokenName() {
-        return tokenName;
-    }
-
-    public String getTokenSymbol() {
-        return tokenSymbol;
-    }
-
-    public int getTransactionIndex() {
-        return transactionIndex;
-    }
-
-    public long getGasPrice() {
-        return gasPrice;
-    }
-
-    public long getCumulativeGasUsed() {
-        return cumulativeGasUsed;
-    }
-
-    public long getConfirmations() {
-        return confirmations;
-    }
-
-    @Override
-    public String toString() {
-        return "BaseTxToken{" +
-                "nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
-                ", tokenName='" + tokenName + '\'' +
-                ", tokenSymbol='" + tokenSymbol + '\'' +
-                ", transactionIndex=" + transactionIndex +
-                ", gasPrice=" + gasPrice +
-                ", cumulativeGasUsed=" + cumulativeGasUsed +
-                ", confirmations=" + confirmations +
-                '}' + super.toString();
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/TxErc1155.java b/src/main/java/io/api/etherscan/model/TxErc1155.java
deleted file mode 100644
index b926b1b..0000000
--- a/src/main/java/io/api/etherscan/model/TxErc1155.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.api.etherscan.model;
-
-import java.math.BigInteger;
-
-public class TxErc1155 extends BaseTxToken {
-
-    private BigInteger tokenID;
-    private BigInteger tokenValue;
-
-    public BigInteger getTokenID() {
-        return tokenID;
-    }
-
-    public BigInteger getTokenValue() {
-        return tokenValue;
-    }
-
-    @Override
-    public String toString() {
-        return "TxErc1155{" +
-                "tokenID=" + tokenID +
-                ", tokenValue=" + tokenValue +
-                '}' + super.toString();
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/TxErc20.java b/src/main/java/io/api/etherscan/model/TxErc20.java
deleted file mode 100644
index 9c4e65e..0000000
--- a/src/main/java/io/api/etherscan/model/TxErc20.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package io.api.etherscan.model;
-
-import java.math.BigInteger;
-
-public class TxErc20 extends BaseTxToken {
-
-    private BigInteger tokenDecimal;
-
-    public BigInteger getTokenDecimal() {
-        return tokenDecimal;
-    }
-
-    @Override
-    public String toString() {
-        return "TxErc20{" +
-                "tokenDecimal=" + tokenDecimal +
-                '}' + super.toString();
-    }
-}
diff --git a/src/main/java/io/api/etherscan/model/TxErc721.java b/src/main/java/io/api/etherscan/model/TxErc721.java
deleted file mode 100644
index 9f70c3d..0000000
--- a/src/main/java/io/api/etherscan/model/TxErc721.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.api.etherscan.model;
-
-import java.math.BigInteger;
-
-public class TxErc721 extends BaseTxToken {
-
-    private BigInteger tokenID;
-    private BigInteger tokenDecimal;
-
-    public BigInteger getTokenID() {
-        return tokenID;
-    }
-
-    public BigInteger getTokenDecimal() {
-        return tokenDecimal;
-    }
-
-    @Override
-    public String toString() {
-        return "TxErc721{" +
-                "tokenID=" + tokenID +
-                ", tokenDecimal=" + tokenDecimal +
-                '}' + super.toString();
-    }
-}

From a9dd8e0d2d84b64fef15980715c15220f3cd4f9b Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 03:45:36 +0300
Subject: [PATCH 27/67] [2.0.0-SNAPSHOT] Javadoc improvements

---
 .../api/etherscan/EthScanAPIBuilder.java          |  5 ++---
 .../api/etherscan/http/impl/UrlEthHttpClient.java |  5 +++--
 .../etherscan/manager/RequestQueueManager.java    | 15 +++++++++++++--
 .../io/goodforgod/api/etherscan/ApiRunner.java    |  4 ++--
 .../api/etherscan/proxy/ProxyBlockApiTests.java   |  2 +-
 5 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index 501bdb1..c9c1102 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -5,7 +5,6 @@
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
-import io.goodforgod.api.etherscan.manager.impl.FakeRequestQueueManager;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import io.goodforgod.gson.configuration.GsonConfiguration;
 import java.util.function.Supplier;
@@ -24,7 +23,7 @@ final class EthScanAPIBuilder implements EtherScanAPI.Builder {
 
     private String apiKey = DEFAULT_KEY;
     private EthNetwork ethNetwork = EthNetworks.MAINNET;
-    private RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
+    private RequestQueueManager queueManager = RequestQueueManager.ANONYMOUS;
     private Supplier<EthHttpClient> ethHttpClientSupplier = DEFAULT_SUPPLIER;
     private Supplier<Converter> converterSupplier = () -> new Converter() {
 
@@ -42,7 +41,7 @@ public EtherScanAPI.Builder withApiKey(@NotNull String apiKey) {
 
         this.apiKey = apiKey;
         if (!DEFAULT_KEY.equals(apiKey)) {
-            queueManager = new FakeRequestQueueManager();
+            queueManager = RequestQueueManager.UNLIMITED;
         }
         return this;
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
index 4178be7..57c970b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
@@ -20,6 +20,7 @@
 import java.util.Map;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.InflaterInputStream;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Http client implementation
@@ -82,7 +83,7 @@ private HttpURLConnection buildConnection(URI uri, String method) throws IOExcep
     }
 
     @Override
-    public String get(URI uri) {
+    public @NotNull String get(@NotNull URI uri) {
         try {
             final HttpURLConnection connection = buildConnection(uri, "GET");
             final int status = connection.getResponseCode();
@@ -105,7 +106,7 @@ public String get(URI uri) {
     }
 
     @Override
-    public String post(URI uri, byte[] body) {
+    public @NotNull String post(@NotNull URI uri, byte[] body) {
         try {
             final HttpURLConnection connection = buildConnection(uri, "POST");
             final int contentLength = body.length;
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index 6b2740a..f19603f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -1,5 +1,6 @@
 package io.goodforgod.api.etherscan.manager;
 
+import io.goodforgod.api.etherscan.manager.impl.FakeRequestQueueManager;
 import io.goodforgod.api.etherscan.manager.impl.SemaphoreRequestQueueManager;
 import java.time.Duration;
 
@@ -12,8 +13,18 @@
  */
 public interface RequestQueueManager extends AutoCloseable {
 
-    RequestQueueManager DEFAULT = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5005L));
-    RequestQueueManager PERSONAL = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1005L));
+    /**
+     * Is used by default when no API KEY is provided
+     */
+    RequestQueueManager ANONYMOUS = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5005L));
+
+    /**
+     * Is available for all registered free API KEYs
+     * <a href="https://docs.etherscan.io/getting-started/viewing-api-usage-statistics">Free API KEY</a>
+     */
+    RequestQueueManager FREE_PLAN = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1005L));
+
+    RequestQueueManager UNLIMITED = new FakeRequestQueueManager();
 
     /**
      * Waits in queue for chance to take turn
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index d63bc73..d28a8e0 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -20,8 +20,8 @@ public class ApiRunner extends Assertions {
                 .orElse(DEFAULT_KEY);
 
         final RequestQueueManager queueManager = (DEFAULT_KEY.equals(API_KEY))
-                ? RequestQueueManager.DEFAULT
-                : RequestQueueManager.PERSONAL;
+                ? RequestQueueManager.ANONYMOUS
+                : RequestQueueManager.FREE_PLAN;
 
         API = EtherScanAPI.builder()
                 .withApiKey(ApiRunner.API_KEY)
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
index 44d786d..10dc6fd 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
@@ -17,7 +17,7 @@ class ProxyBlockApiTests extends ApiRunner {
     private final EtherScanAPI api;
 
     ProxyBlockApiTests() {
-        final RequestQueueManager queueManager = RequestQueueManager.DEFAULT;
+        final RequestQueueManager queueManager = RequestQueueManager.ANONYMOUS;
         this.api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
                 .build();
     }

From 225b21165f9bfa6defc4566a2f858f6f010498a0 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 12:47:36 +0300
Subject: [PATCH 28/67] [2.0.0-SNAPSHOT] Tx Responses restored GasOracle
 refactored and improved ModelBuilderTests added

---
 .../goodforgod/api/etherscan/model/Block.java |   2 +
 .../api/etherscan/model/BlockUncle.java       |   6 +
 .../api/etherscan/model/GasOracle.java        |  72 +++--
 .../goodforgod/api/etherscan/model/Log.java   |   2 +
 .../goodforgod/api/etherscan/model/Price.java |  10 +-
 .../api/etherscan/model/Status.java           |   2 +
 .../io/goodforgod/api/etherscan/model/Tx.java |   2 +
 .../api/etherscan/model/TxErc1155.java        |  18 +-
 .../api/etherscan/model/TxErc20.java          |  18 +-
 .../api/etherscan/model/TxErc721.java         |  18 +-
 .../api/etherscan/model/TxInternal.java       |   4 +-
 .../api/etherscan/model/proxy/BlockProxy.java |   2 +
 .../etherscan/model/proxy/ReceiptProxy.java   |   2 +
 .../api/etherscan/model/proxy/TxProxy.java    |   2 +
 .../model/response/TxErc1155ResponseTO.java   |  11 +
 .../model/response/TxErc20ResponseTO.java     |  11 +
 .../model/response/TxErc721ResponseTO.java    |  11 +
 .../api/etherscan/block/BlockApiTests.java    |   2 +-
 .../etherscan/model/ModelBuilderTests.java    | 265 +++++++++++++++++-
 .../etherscan/proxy/ProxyBlockApiTests.java   |   2 +-
 .../api/etherscan/proxy/ProxyTxApiTests.java  |   2 +-
 .../proxy/ProxyTxReceiptApiTests.java         |   2 +-
 .../statistic/StatisticPriceApiTests.java     |   2 +-
 .../transaction/TransactionExecApiTests.java  |   2 +-
 24 files changed, 407 insertions(+), 63 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java

diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Block.java b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
index 129ca39..d46fb44 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Block.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
@@ -18,6 +18,8 @@ public class Block {
     @Expose(deserialize = false, serialize = false)
     LocalDateTime _timeStamp;
 
+    protected Block() {}
+
     // <editor-fold desc="Getter">
     public long getBlockNumber() {
         return blockNumber;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
index 5cf1a3e..02ddc28 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
@@ -18,6 +18,8 @@ public static class Uncle {
         private BigInteger blockreward;
         private int unclePosition;
 
+        private Uncle() {}
+
         // <editor-fold desc="Getters">
         public String getMiner() {
             return miner;
@@ -113,6 +115,10 @@ public Uncle build() {
     private List<Uncle> uncles;
     private String uncleInclusionReward;
 
+    protected BlockUncle() {
+        super();
+    }
+
     // <editor-fold desc="Getters">
     public boolean isEmpty() {
         return getBlockNumber() == 0 && getBlockReward() == null
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
index 69fa6b5..67dd82a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
@@ -1,7 +1,11 @@
 package io.goodforgod.api.etherscan.model;
 
+import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * @author Abhay Gupta
@@ -16,28 +20,32 @@ public class GasOracle {
     private Double suggestBaseFee;
     private String gasUsedRatio;
 
+    protected GasOracle() {}
+
     public Long getLastBlock() {
         return LastBlock;
     }
 
-    public BigInteger getSafeGasPriceInWei() {
-        return BigInteger.valueOf(SafeGasPrice).multiply(BigInteger.TEN.pow(9));
+    public Wei getSafeGasPriceInWei() {
+        return new Wei(BigInteger.valueOf(SafeGasPrice).multiply(BigInteger.TEN.pow(9)));
     }
 
-    public BigInteger getProposeGasPriceInWei() {
-        return BigInteger.valueOf(ProposeGasPrice).multiply(BigInteger.TEN.pow(9));
+    public Wei getProposeGasPriceInWei() {
+        return new Wei(BigInteger.valueOf(ProposeGasPrice).multiply(BigInteger.TEN.pow(9)));
     }
 
-    public BigInteger getFastGasPriceInWei() {
-        return BigInteger.valueOf(FastGasPrice).multiply(BigInteger.TEN.pow(9));
+    public Wei getFastGasPriceInWei() {
+        return new Wei(BigInteger.valueOf(FastGasPrice).multiply(BigInteger.TEN.pow(9)));
     }
 
     public Double getSuggestBaseFee() {
         return suggestBaseFee;
     }
 
-    public String getGasUsedRatio() {
-        return gasUsedRatio;
+    public List<BigDecimal> getGasUsedRatio() {
+        return Arrays.stream(gasUsedRatio.split(","))
+                .map(BigDecimal::new)
+                .collect(Collectors.toList());
     }
 
     @Override
@@ -75,32 +83,32 @@ public static GasOracleBuilder builder() {
 
     public static final class GasOracleBuilder {
 
-        private Long LastBlock;
-        private Integer SafeGasPrice;
-        private Integer ProposeGasPrice;
-        private Integer FastGasPrice;
+        private Long lastBlock;
+        private Wei safeGasPrice;
+        private Wei proposeGasPrice;
+        private Wei fastGasPrice;
         private Double suggestBaseFee;
-        private String gasUsedRatio;
+        private List<BigDecimal> gasUsedRatio;
 
         private GasOracleBuilder() {}
 
-        public GasOracleBuilder withLastBlock(Long LastBlock) {
-            this.LastBlock = LastBlock;
+        public GasOracleBuilder withLastBlock(Long lastBlock) {
+            this.lastBlock = lastBlock;
             return this;
         }
 
-        public GasOracleBuilder withSafeGasPrice(Integer SafeGasPrice) {
-            this.SafeGasPrice = SafeGasPrice;
+        public GasOracleBuilder withSafeGasPrice(Wei safeGasPrice) {
+            this.safeGasPrice = safeGasPrice;
             return this;
         }
 
-        public GasOracleBuilder withProposeGasPrice(Integer ProposeGasPrice) {
-            this.ProposeGasPrice = ProposeGasPrice;
+        public GasOracleBuilder withProposeGasPrice(Wei proposeGasPrice) {
+            this.proposeGasPrice = proposeGasPrice;
             return this;
         }
 
-        public GasOracleBuilder withFastGasPrice(Integer FastGasPrice) {
-            this.FastGasPrice = FastGasPrice;
+        public GasOracleBuilder withFastGasPrice(Wei fastGasPrice) {
+            this.fastGasPrice = fastGasPrice;
             return this;
         }
 
@@ -109,19 +117,29 @@ public GasOracleBuilder withSuggestBaseFee(Double suggestBaseFee) {
             return this;
         }
 
-        public GasOracleBuilder withGasUsedRatio(String gasUsedRatio) {
+        public GasOracleBuilder withGasUsedRatio(List<BigDecimal> gasUsedRatio) {
             this.gasUsedRatio = gasUsedRatio;
             return this;
         }
 
         public GasOracle build() {
             GasOracle gasOracle = new GasOracle();
-            gasOracle.ProposeGasPrice = this.ProposeGasPrice;
-            gasOracle.LastBlock = this.LastBlock;
+            gasOracle.LastBlock = this.lastBlock;
             gasOracle.suggestBaseFee = this.suggestBaseFee;
-            gasOracle.SafeGasPrice = this.SafeGasPrice;
-            gasOracle.FastGasPrice = this.FastGasPrice;
-            gasOracle.gasUsedRatio = this.gasUsedRatio;
+            if (this.proposeGasPrice != null) {
+                gasOracle.ProposeGasPrice = this.proposeGasPrice.asGwei().intValue();
+            }
+            if (this.safeGasPrice != null) {
+                gasOracle.SafeGasPrice = this.safeGasPrice.asGwei().intValue();
+            }
+            if (this.fastGasPrice != null) {
+                gasOracle.FastGasPrice = this.fastGasPrice.asGwei().intValue();
+            }
+            if (this.gasUsedRatio != null) {
+                gasOracle.gasUsedRatio = this.gasUsedRatio.stream()
+                        .map(BigDecimal::toString)
+                        .collect(Collectors.joining(", "));
+            }
             return gasOracle;
         }
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index bd03103..5ed840a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -37,6 +37,8 @@ public class Log {
     @Expose(deserialize = false, serialize = false)
     private Long _logIndex;
 
+    protected Log() {}
+
     // <editor-fold desc="Getters">
     public Long getBlockNumber() {
         if (_blockNumber == null && !BasicUtils.isEmpty(blockNumber)) {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
index 9c72792..b24fc65 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -19,6 +19,8 @@ public class Price {
     @Expose(deserialize = false, serialize = false)
     private LocalDateTime _ethbtc_timestamp;
 
+    protected Price() {}
+
     public double inUsd() {
         return ethusd;
     }
@@ -101,22 +103,22 @@ public static final class PriceBuilder {
 
         private PriceBuilder() {}
 
-        public PriceBuilder withEthusd(double ethusd) {
+        public PriceBuilder withEthUsd(double ethusd) {
             this.ethusd = ethusd;
             return this;
         }
 
-        public PriceBuilder withEthbtc(double ethbtc) {
+        public PriceBuilder withEthBtc(double ethbtc) {
             this.ethbtc = ethbtc;
             return this;
         }
 
-        public PriceBuilder withEthusdTimestamp(LocalDateTime ethusdTimestamp) {
+        public PriceBuilder withEthUsdTimestamp(LocalDateTime ethusdTimestamp) {
             this.ethusdTimestamp = ethusdTimestamp;
             return this;
         }
 
-        public PriceBuilder withEthbtcTimestamp(LocalDateTime ethbtcTimestamp) {
+        public PriceBuilder withEthBtcTimestamp(LocalDateTime ethbtcTimestamp) {
             this.ethbtcTimestamp = ethbtcTimestamp;
             return this;
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Status.java b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
index 8cdc704..eaf9b8a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Status.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
@@ -16,6 +16,8 @@ public class Status {
     private int isError;
     private String errDescription;
 
+    protected Status() {}
+
     public boolean haveError() {
         return isError == 1;
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 65c24ba..7e09768 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -22,6 +22,8 @@ public class Tx extends BaseTx {
     private String isError;
     private String txreceipt_status;
 
+    protected Tx() {}
+
     // <editor-fold desc="Getters">
     public BigInteger getValue() {
         return value;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
index 84e2d40..edf578f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -18,10 +18,12 @@ public class TxErc1155 extends BaseTx {
     private String tokenSymbol;
     private String tokenValue;
     private int transactionIndex;
-    private long gasPrice;
-    private long cumulativeGasUsed;
+    private BigInteger gasPrice;
+    private BigInteger cumulativeGasUsed;
     private long confirmations;
 
+    protected TxErc1155() {}
+
     // <editor-fold desc="Getters">
     public long getNonce() {
         return nonce;
@@ -51,11 +53,11 @@ public int getTransactionIndex() {
         return transactionIndex;
     }
 
-    public long getGasPrice() {
+    public BigInteger getGasPrice() {
         return gasPrice;
     }
 
-    public long getCumulativeGasUsed() {
+    public BigInteger getCumulativeGasUsed() {
         return cumulativeGasUsed;
     }
 
@@ -120,8 +122,8 @@ public static final class TxErc1155Builder {
         private String tokenSymbol;
         private String tokenValue;
         private int transactionIndex;
-        private long gasPrice;
-        private long cumulativeGasUsed;
+        private BigInteger gasPrice;
+        private BigInteger cumulativeGasUsed;
         private long confirmations;
 
         private TxErc1155Builder() {}
@@ -206,12 +208,12 @@ public TxErc1155Builder withTransactionIndex(int transactionIndex) {
             return this;
         }
 
-        public TxErc1155Builder withGasPrice(long gasPrice) {
+        public TxErc1155Builder withGasPrice(BigInteger gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public TxErc1155Builder withCumulativeGasUsed(long cumulativeGasUsed) {
+        public TxErc1155Builder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index f51b855..9342c8e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -18,10 +18,12 @@ public class TxErc20 extends BaseTx {
     private String tokenSymbol;
     private String tokenDecimal;
     private int transactionIndex;
-    private long gasPrice;
-    private long cumulativeGasUsed;
+    private BigInteger gasPrice;
+    private BigInteger cumulativeGasUsed;
     private long confirmations;
 
+    protected TxErc20() {}
+
     // <editor-fold desc="Getters">
     public long getNonce() {
         return nonce;
@@ -51,11 +53,11 @@ public int getTransactionIndex() {
         return transactionIndex;
     }
 
-    public long getGasPrice() {
+    public BigInteger getGasPrice() {
         return gasPrice;
     }
 
-    public long getCumulativeGasUsed() {
+    public BigInteger getCumulativeGasUsed() {
         return cumulativeGasUsed;
     }
 
@@ -120,8 +122,8 @@ public static final class TxERC20Builder {
         private String tokenSymbol;
         private String tokenDecimal;
         private int transactionIndex;
-        private long gasPrice;
-        private long cumulativeGasUsed;
+        private BigInteger gasPrice;
+        private BigInteger cumulativeGasUsed;
         private long confirmations;
 
         private TxERC20Builder() {}
@@ -206,12 +208,12 @@ public TxERC20Builder withTransactionIndex(int transactionIndex) {
             return this;
         }
 
-        public TxERC20Builder withGasPrice(long gasPrice) {
+        public TxERC20Builder withGasPrice(BigInteger gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public TxERC20Builder withCumulativeGasUsed(long cumulativeGasUsed) {
+        public TxERC20Builder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 8fb2467..1276b71 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -18,10 +18,12 @@ public class TxErc721 extends BaseTx {
     private String tokenSymbol;
     private String tokenDecimal;
     private int transactionIndex;
-    private long gasPrice;
-    private long cumulativeGasUsed;
+    private BigInteger gasPrice;
+    private BigInteger cumulativeGasUsed;
     private long confirmations;
 
+    protected TxErc721() {}
+
     // <editor-fold desc="Getters">
     public long getNonce() {
         return nonce;
@@ -51,11 +53,11 @@ public int getTransactionIndex() {
         return transactionIndex;
     }
 
-    public long getGasPrice() {
+    public BigInteger getGasPrice() {
         return gasPrice;
     }
 
-    public long getCumulativeGasUsed() {
+    public BigInteger getCumulativeGasUsed() {
         return cumulativeGasUsed;
     }
 
@@ -120,8 +122,8 @@ public static final class TxERC721Builder {
         private String tokenSymbol;
         private String tokenDecimal;
         private int transactionIndex;
-        private long gasPrice;
-        private long cumulativeGasUsed;
+        private BigInteger gasPrice;
+        private BigInteger cumulativeGasUsed;
         private long confirmations;
 
         private TxERC721Builder() {}
@@ -206,12 +208,12 @@ public TxERC721Builder withTransactionIndex(int transactionIndex) {
             return this;
         }
 
-        public TxERC721Builder withGasPrice(long gasPrice) {
+        public TxERC721Builder withGasPrice(BigInteger gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public TxERC721Builder withCumulativeGasUsed(long cumulativeGasUsed) {
+        public TxERC721Builder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index 84e10b3..68bdebf 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -17,6 +17,8 @@ public class TxInternal extends BaseTx {
     private int isError;
     private String errCode;
 
+    protected TxInternal() {}
+
     // <editor-fold desc="Getters">
     public BigInteger getValue() {
         return value;
@@ -102,7 +104,7 @@ public TxInternalBuilder withBlockNumber(long blockNumber) {
             return this;
         }
 
-        public TxInternalBuilder with_timeStamp(LocalDateTime timeStamp) {
+        public TxInternalBuilder withTimeStamp(LocalDateTime timeStamp) {
             this.timeStamp = timeStamp;
             return this;
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index 0e6ff3a..1eb46f3 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -47,6 +47,8 @@ public class BlockProxy {
     private String transactionsRoot;
     private List<TxProxy> transactions;
 
+    protected BlockProxy() {}
+
     // <editor-fold desc="Getters">
     public Long getNumber() {
         if (_number == null && !BasicUtils.isEmpty(number))
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index 73a21b6..a57ce36 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -34,6 +34,8 @@ public class ReceiptProxy {
     private List<Log> logs;
     private String logsBloom;
 
+    protected ReceiptProxy() {}
+
     // <editor-fold desc="Getters">
     public String getRoot() {
         return root;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index 52fe41b..b6324e1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -35,6 +35,8 @@ public class TxProxy {
     @Expose(deserialize = false, serialize = false)
     private Long _blockNumber;
 
+    protected TxProxy() {}
+
     // <editor-fold desc="Getters">
     public String getTo() {
         return to;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
new file mode 100644
index 0000000..3bf9d49
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc1155ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxErc1155;
+
+/**
+ * @author GoodforGod
+ * @since 14.05.2023
+ */
+public class TxErc1155ResponseTO extends BaseListResponseTO<TxErc1155> {
+
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
new file mode 100644
index 0000000..d5d3f6e
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc20ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxErc20;
+
+/**
+ * @author GoodforGod
+ * @since 29.10.2018
+ */
+public class TxErc20ResponseTO extends BaseListResponseTO<TxErc20> {
+
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java
new file mode 100644
index 0000000..27518ae
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/TxErc721ResponseTO.java
@@ -0,0 +1,11 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.TxErc721;
+
+/**
+ * @author GoodforGod
+ * @since 14.05.2023
+ */
+public class TxErc721ResponseTO extends BaseListResponseTO<TxErc721> {
+
+}
diff --git a/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTests.java b/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTests.java
index 3e84ab7..7a923aa 100644
--- a/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/block/BlockApiTests.java
@@ -25,7 +25,7 @@ void correct() {
         assertNotEquals(-1, uncle.get().getUncles().get(0).getUnclePosition());
         assertNotNull(uncle.get().toString());
 
-        BlockUncle empty = new BlockUncle();
+        BlockUncle empty = BlockUncle.builder().build();
         assertNotEquals(uncle.get().hashCode(), empty.hashCode());
         assertNotEquals(uncle.get(), empty);
         assertTrue(empty.isEmpty());
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index 6f5fc22..7db6aae 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -1,7 +1,270 @@
 package io.goodforgod.api.etherscan.model;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.util.Collections;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
 /**
  * @author Anton Kurako (GoodforGod)
  * @since 14.05.2023
  */
-class ModelBuilderTests {}
+class ModelBuilderTests extends Assertions {
+
+    @Test
+    void abiBuilder() {
+        Abi value = Abi.builder()
+                .withContractAbi("1")
+                .withIsVerified(true)
+                .build();
+
+        assertNotNull(value);
+        assertTrue(value.isVerified());
+        assertEquals("1", value.getContractAbi());
+    }
+
+    @Test
+    void blockBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        Block value = Block.builder()
+                .withBlockNumber(1)
+                .withBlockReward(BigInteger.ONE)
+                .withTimeStamp(timestamp)
+                .build();
+
+        assertNotNull(value);
+        assertEquals(1, value.getBlockNumber());
+        assertEquals(BigInteger.ONE, value.getBlockReward());
+        assertEquals(timestamp, value.getTimeStamp());
+    }
+
+    @Test
+    void blockUncleBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        BlockUncle value = BlockUncle.builder()
+                .withBlockNumber(1)
+                .withBlockReward(BigInteger.ONE)
+                .withTimeStamp(timestamp)
+                .withBlockMiner("1")
+                .withUncleInclusionReward("1")
+                .withUncles(Collections.singletonList(BlockUncle.Uncle.builder()
+                        .withBlockreward(BigInteger.ONE)
+                        .withMiner("1")
+                        .withUnclePosition(1)
+                        .build()))
+                .build();
+
+        assertNotNull(value);
+        assertEquals(1, value.getBlockNumber());
+        assertEquals(BigInteger.ONE, value.getBlockReward());
+        assertEquals(timestamp, value.getTimeStamp());
+    }
+
+    @Test
+    void gasOracleBuilder() {
+        GasOracle value = GasOracle.builder()
+                .withFastGasPrice(new Wei(1000000000))
+                .withProposeGasPrice(new Wei(1000000000))
+                .withSafeGasPrice(new Wei(1000000000))
+                .withGasUsedRatio(Collections.singletonList(new BigDecimal(1)))
+                .withLastBlock(1L)
+                .withSuggestBaseFee(1.0)
+                .build();
+
+        assertNotNull(value);
+        assertEquals(new Wei(1000000000), value.getFastGasPriceInWei());
+    }
+
+    @Test
+    void logBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        Log value = Log.builder()
+                .withAddress("1")
+                .withBlockNumber(1L)
+                .withData("1")
+                .withGasPrice(BigInteger.ONE)
+                .withGasUsed(BigInteger.ONE)
+                .withLogIndex(1L)
+                .withTimeStamp(timestamp)
+                .withTransactionHash("1")
+                .withTransactionIndex(1L)
+                .withTopics(Collections.singletonList("1"))
+                .build();
+
+        assertNotNull(value);
+        assertEquals(1, value.getTopics().size());
+    }
+
+    @Test
+    void priceBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        Price value = Price.builder()
+                .withEthBtc(1.0)
+                .withEthUsd(1.0)
+                .withEthBtcTimestamp(timestamp)
+                .withEthUsdTimestamp(timestamp)
+                .build();
+
+        assertNotNull(value);
+        assertEquals(1.0, value.inUsd());
+        assertEquals(1.0, value.inBtc());
+    }
+
+    @Test
+    void statusBuilder() {
+        Status value = Status.builder()
+                .withIsError(1)
+                .withErrDescription("1")
+                .build();
+
+        assertNotNull(value);
+        assertTrue(value.haveError());
+        assertEquals("1", value.getErrDescription());
+    }
+
+    @Test
+    void txBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        Tx value = Tx.builder()
+                .withBlockHash("1")
+                .withBlockNumber(1L)
+                .withConfirmations(1L)
+                .withContractAddress("1")
+                .withCumulativeGasUsed(BigInteger.ONE)
+                .withFrom("1")
+                .withTo("1")
+                .withGas(BigInteger.ONE)
+                .withGasPrice(BigInteger.ONE)
+                .withGasUsed(BigInteger.ONE)
+                .withHash("1")
+                .withInput("1")
+                .withIsError("1")
+                .withNonce(1L)
+                .withTimeStamp(timestamp)
+                .withValue(BigInteger.ONE)
+                .withTransactionIndex(1)
+                .withTxreceiptStatus("1")
+                .build();
+
+        assertNotNull(value);
+        assertTrue(value.haveError());
+        assertEquals("1", value.getTo());
+        assertEquals("1", value.getFrom());
+    }
+
+    @Test
+    void txErc20Builder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        TxErc20 value = TxErc20.builder()
+                .withBlockHash("1")
+                .withBlockNumber(1L)
+                .withConfirmations(1L)
+                .withContractAddress("1")
+                .withCumulativeGasUsed(BigInteger.ONE)
+                .withFrom("1")
+                .withTo("1")
+                .withGas(BigInteger.ONE)
+                .withGasPrice(BigInteger.ONE)
+                .withGasUsed(BigInteger.ONE)
+                .withHash("1")
+                .withInput("1")
+                .withTokenName("1")
+                .withTokenSymbol("1")
+                .withTokenDecimal("1")
+                .withNonce(1L)
+                .withTimeStamp(timestamp)
+                .withValue(BigInteger.ONE)
+                .withTransactionIndex(1)
+                .build();
+
+        assertNotNull(value);
+        assertEquals("1", value.getTo());
+        assertEquals("1", value.getFrom());
+    }
+
+    @Test
+    void txErc721Builder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        TxErc721 value = TxErc721.builder()
+                .withBlockHash("1")
+                .withBlockNumber(1L)
+                .withConfirmations(1L)
+                .withContractAddress("1")
+                .withCumulativeGasUsed(BigInteger.ONE)
+                .withFrom("1")
+                .withTo("1")
+                .withGas(BigInteger.ONE)
+                .withGasPrice(BigInteger.ONE)
+                .withGasUsed(BigInteger.ONE)
+                .withHash("1")
+                .withInput("1")
+                .withTokenName("1")
+                .withTokenSymbol("1")
+                .withTokenDecimal("1")
+                .withTokenID("1")
+                .withNonce(1L)
+                .withTimeStamp(timestamp)
+                .withTransactionIndex(1)
+                .build();
+
+        assertNotNull(value);
+        assertEquals("1", value.getTo());
+        assertEquals("1", value.getFrom());
+    }
+
+    @Test
+    void txErc1155Builder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        TxErc1155 value = TxErc1155.builder()
+                .withBlockHash("1")
+                .withBlockNumber(1L)
+                .withConfirmations(1L)
+                .withContractAddress("1")
+                .withCumulativeGasUsed(BigInteger.ONE)
+                .withFrom("1")
+                .withTo("1")
+                .withGas(BigInteger.ONE)
+                .withGasPrice(BigInteger.ONE)
+                .withGasUsed(BigInteger.ONE)
+                .withHash("1")
+                .withInput("1")
+                .withTokenName("1")
+                .withTokenSymbol("1")
+                .withTokenDecimal("1")
+                .withTokenID("1")
+                .withNonce(1L)
+                .withTimeStamp(timestamp)
+                .withTransactionIndex(1)
+                .build();
+
+        assertNotNull(value);
+        assertEquals("1", value.getTo());
+        assertEquals("1", value.getFrom());
+    }
+
+    @Test
+    void txInternalBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        TxInternal value = TxInternal.builder()
+                .withBlockNumber(1L)
+                .withContractAddress("1")
+                .withFrom("1")
+                .withTo("1")
+                .withGas(BigInteger.ONE)
+                .withGasUsed(BigInteger.ONE)
+                .withHash("1")
+                .withInput("1")
+                .withTimeStamp(timestamp)
+                .withErrCode("1")
+                .withIsError(1)
+                .withTraceId("1")
+                .withType("1")
+                .build();
+
+        assertNotNull(value);
+        assertEquals("1", value.getTo());
+        assertEquals("1", value.getFrom());
+    }
+}
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
index 10dc6fd..874ccc0 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
@@ -50,7 +50,7 @@ void correct() {
         assertNotNull(proxy.getUncles());
         assertNotNull(proxy.toString());
 
-        BlockProxy empty = new BlockProxy();
+        BlockProxy empty = BlockProxy.builder().build();
         assertNotEquals(proxy, empty);
         assertNotEquals(proxy.hashCode(), empty.hashCode());
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTests.java
index 6c7dbb7..b20369e 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxApiTests.java
@@ -24,7 +24,7 @@ void correctByHash() {
         assertNotNull(tx.get().getBlockNumber());
         assertNotNull(tx.get().toString());
 
-        TxProxy empty = new TxProxy();
+        TxProxy empty = TxProxy.builder().build();
         assertNotEquals(tx.get(), empty);
         assertNotEquals(tx.get().hashCode(), empty.hashCode());
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
index 7a6624c..e4322f2 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
@@ -32,7 +32,7 @@ void correct() {
         assertNull(infoProxy.get().getContractAddress());
         assertNotNull(infoProxy.get().toString());
 
-        ReceiptProxy empty = new ReceiptProxy();
+        ReceiptProxy empty = ReceiptProxy.builder().build();
         assertNotEquals(empty, infoProxy.get());
         assertNotEquals(empty.hashCode(), infoProxy.get().hashCode());
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
index 37e0ec0..3525e21 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
@@ -20,7 +20,7 @@ void correct() {
         assertNotEquals(0.0, price.inUsd());
         assertNotNull(price.toString());
 
-        Price empty = new Price();
+        Price empty = Price.builder().build();
         assertNotEquals(price, empty);
         assertNotEquals(price.hashCode(), empty.hashCode());
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTests.java b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTests.java
index eb595c3..23e512c 100644
--- a/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/transaction/TransactionExecApiTests.java
@@ -20,7 +20,7 @@ void correct() {
         assertNotNull(status.get().getErrDescription());
         assertNotNull(status.get().toString());
 
-        Status empty = new Status();
+        Status empty = Status.builder().build();
         assertNotEquals(empty, status.get());
         assertNotEquals(empty.hashCode(), status.get().hashCode());
     }

From aa251291f27a11347fc7f63fdbcb2ecf6c4c4de5 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 12:52:59 +0300
Subject: [PATCH 29/67] [2.0.0-SNAPSHOT] CI key env fixed

---
 .github/workflows/gradle.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 3eb55f0..31c42f0 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -35,13 +35,13 @@ jobs:
         if: matrix.java == '11'
         run: ./gradlew test jacocoTestReport
         env:
-          API_KEY: ${{ secrets.ETHERSCAN_API_KEY_1 }}
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_1 }}
 
       - name: Test
         if: matrix.java == '17'
         run: ./gradlew test jacocoTestReport
         env:
-          API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
 
       - name: SonarQube
         if: matrix.java == '17'

From 873f5828e525e109190b409295b0ef507a68f053 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 13:04:56 +0300
Subject: [PATCH 30/67] [2.0.0-SNAPSHOT] Builders NPE fixes Hashcode & Equals
 improved

---
 .../goodforgod/api/etherscan/model/Abi.java   | 19 ++-----
 .../api/etherscan/model/Balance.java          | 14 ++---
 .../goodforgod/api/etherscan/model/Block.java | 13 ++---
 .../api/etherscan/model/BlockUncle.java       | 51 ++++---------------
 .../goodforgod/api/etherscan/model/Log.java   | 51 +++++++------------
 .../goodforgod/api/etherscan/model/Price.java | 51 +++++++------------
 .../io/goodforgod/api/etherscan/model/Tx.java |  6 ++-
 .../api/etherscan/model/TxErc1155.java        |  6 ++-
 .../api/etherscan/model/TxErc20.java          |  6 ++-
 .../api/etherscan/model/TxErc721.java         |  6 ++-
 .../api/etherscan/model/TxInternal.java       |  6 ++-
 .../goodforgod/api/etherscan/model/Wei.java   |  7 +--
 .../api/etherscan/model/proxy/BlockProxy.java | 18 ++++---
 .../etherscan/model/proxy/ReceiptProxy.java   | 12 +++--
 .../api/etherscan/model/proxy/TxProxy.java    | 12 +++--
 15 files changed, 108 insertions(+), 170 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
index 3fce40a..3536bf9 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan.model;
 
 import io.goodforgod.api.etherscan.util.BasicUtils;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -40,27 +41,15 @@ public boolean isVerified() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Abi))
             return false;
-
         Abi abi = (Abi) o;
-
-        if (isVerified != abi.isVerified)
-            return false;
-        return contractAbi != null
-                ? contractAbi.equals(abi.contractAbi)
-                : abi.contractAbi == null;
+        return isVerified == abi.isVerified && Objects.equals(contractAbi, abi.contractAbi);
     }
 
     @Override
     public int hashCode() {
-        int result = contractAbi != null
-                ? contractAbi.hashCode()
-                : 0;
-        result = 31 * result + (isVerified
-                ? 1
-                : 0);
-        return result;
+        return Objects.hash(contractAbi, isVerified);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
index 38379e6..4de8a54 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
@@ -48,23 +48,15 @@ public BigInteger getEther() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Balance))
             return false;
-
         Balance balance1 = (Balance) o;
-
-        if (!balance.equals(balance1.balance))
-            return false;
-        return Objects.equals(address, balance1.address);
+        return Objects.equals(balance, balance1.balance) && Objects.equals(address, balance1.address);
     }
 
     @Override
     public int hashCode() {
-        int result = balance.hashCode();
-        result = 31 * result + (address != null
-                ? address.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(balance, address);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Block.java b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
index d46fb44..95bfbcb 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Block.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
@@ -5,6 +5,7 @@
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -40,17 +41,15 @@ public BigInteger getBlockReward() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Block))
             return false;
-
         Block block = (Block) o;
-
         return blockNumber == block.blockNumber;
     }
 
     @Override
     public int hashCode() {
-        return (int) (blockNumber ^ (blockNumber >>> 32));
+        return Objects.hash(blockNumber);
     }
 
     @Override
@@ -98,8 +97,10 @@ public Block build() {
             Block block = new Block();
             block.blockNumber = this.blockNumber;
             block.blockReward = this.blockReward;
-            block._timeStamp = this.timeStamp;
-            block.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timeStamp != null) {
+                block._timeStamp = this.timeStamp;
+                block.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            }
             return block;
         }
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
index 02ddc28..9b110d9 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
@@ -5,6 +5,7 @@
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -38,31 +39,16 @@ public int getUnclePosition() {
         public boolean equals(Object o) {
             if (this == o)
                 return true;
-            if (o == null || getClass() != o.getClass())
+            if (!(o instanceof Uncle))
                 return false;
-
             Uncle uncle = (Uncle) o;
-            if (unclePosition != uncle.unclePosition)
-                return false;
-            if (miner != null
-                    ? !miner.equals(uncle.miner)
-                    : uncle.miner != null)
-                return false;
-            return blockreward != null
-                    ? blockreward.equals(uncle.blockreward)
-                    : uncle.blockreward == null;
+            return unclePosition == uncle.unclePosition && Objects.equals(miner, uncle.miner)
+                    && Objects.equals(blockreward, uncle.blockreward);
         }
 
         @Override
         public int hashCode() {
-            int result = miner != null
-                    ? miner.hashCode()
-                    : 0;
-            result = 31 * result + (blockreward != null
-                    ? blockreward.hashCode()
-                    : 0);
-            result = 31 * result + unclePosition;
-            return result;
+            return Objects.hash(miner, blockreward, unclePosition);
         }
 
         @Override
@@ -139,27 +125,6 @@ public String getUncleInclusionReward() {
     }
     // </editor-fold>
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (o == null || getClass() != o.getClass())
-            return false;
-        if (!super.equals(o))
-            return false;
-
-        BlockUncle that = (BlockUncle) o;
-
-        return getBlockNumber() != 0 && getBlockNumber() == that.getBlockNumber();
-    }
-
-    @Override
-    public int hashCode() {
-        int result = super.hashCode();
-        result = (int) (31 * result + getBlockNumber());
-        return result;
-    }
-
     @Override
     public String toString() {
         return "UncleBlock{" +
@@ -223,8 +188,10 @@ public BlockUncle build() {
             blockUncle.blockNumber = this.blockNumber;
             blockUncle.blockReward = this.blockReward;
             blockUncle.blockMiner = this.blockMiner;
-            blockUncle._timeStamp = this.timeStamp;
-            blockUncle.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timeStamp != null) {
+                blockUncle._timeStamp = this.timeStamp;
+                blockUncle.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            }
             return blockUncle;
         }
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index 5ed840a..07e652f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -125,40 +125,17 @@ public Long getLogIndex() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Log))
             return false;
-
         Log log = (Log) o;
-
-        if (!Objects.equals(blockNumber, log.blockNumber))
-            return false;
-        if (!Objects.equals(address, log.address))
-            return false;
-        if (!Objects.equals(transactionHash, log.transactionHash))
-            return false;
-        if (!Objects.equals(timeStamp, log.timeStamp))
-            return false;
-        return Objects.equals(logIndex, log.logIndex);
+        return Objects.equals(blockNumber, log.blockNumber) && Objects.equals(address, log.address)
+                && Objects.equals(transactionHash, log.transactionHash) && Objects.equals(transactionIndex, log.transactionIndex)
+                && Objects.equals(logIndex, log.logIndex);
     }
 
     @Override
     public int hashCode() {
-        int result = blockNumber != null
-                ? blockNumber.hashCode()
-                : 0;
-        result = 31 * result + (address != null
-                ? address.hashCode()
-                : 0);
-        result = 31 * result + (transactionHash != null
-                ? transactionHash.hashCode()
-                : 0);
-        result = 31 * result + (timeStamp != null
-                ? timeStamp.hashCode()
-                : 0);
-        result = 31 * result + (logIndex != null
-                ? logIndex.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(blockNumber, address, transactionHash, transactionIndex, logIndex);
     }
 
     @Override
@@ -255,17 +232,23 @@ public LogBuilder withLogIndex(Long logIndex) {
         public Log build() {
             Log log = new Log();
             log.address = this.address;
-            log.gasPrice = String.valueOf(this.gasPrice);
-            log._gasPrice = this.gasPrice;
+            if (this.gasPrice != null) {
+                log.gasPrice = String.valueOf(this.gasPrice);
+                log._gasPrice = this.gasPrice;
+            }
             log._logIndex = this.logIndex;
             log._transactionIndex = this.transactionIndex;
-            log._gasUsed = this.gasUsed;
             log.blockNumber = String.valueOf(this.blockNumber);
             log.transactionIndex = String.valueOf(this.transactionIndex);
-            log.timeStamp = String.valueOf(this.timeStamp);
+            if (this.timeStamp != null) {
+                log.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+                log._timeStamp = this.timeStamp;
+            }
             log.data = this.data;
-            log.gasUsed = String.valueOf(this.gasUsed);
-            log._timeStamp = this.timeStamp;
+            if (this.gasUsed != null) {
+                log.gasUsed = String.valueOf(this.gasUsed);
+                log._gasUsed = this.gasUsed;
+            }
             log.logIndex = String.valueOf(this.logIndex);
             log._blockNumber = this.blockNumber;
             log.topics = this.topics;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
index b24fc65..4ef4491 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -3,6 +3,7 @@
 import com.google.gson.annotations.Expose;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -30,14 +31,16 @@ public double inBtc() {
     }
 
     public LocalDateTime usdTimestamp() {
-        if (_ethusd_timestamp == null)
+        if (_ethusd_timestamp == null && ethusd_timestamp != null) {
             _ethusd_timestamp = LocalDateTime.ofEpochSecond(Long.parseLong(ethusd_timestamp), 0, ZoneOffset.UTC);
+        }
         return _ethusd_timestamp;
     }
 
     public LocalDateTime btcTimestamp() {
-        if (_ethbtc_timestamp == null)
+        if (_ethbtc_timestamp == null && ethbtc_timestamp != null) {
             _ethbtc_timestamp = LocalDateTime.ofEpochSecond(Long.parseLong(ethbtc_timestamp), 0, ZoneOffset.UTC);
+        }
         return _ethbtc_timestamp;
     }
 
@@ -45,39 +48,17 @@ public LocalDateTime btcTimestamp() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Price))
             return false;
-
         Price price = (Price) o;
-
-        if (Double.compare(price.ethusd, ethusd) != 0)
-            return false;
-        if (Double.compare(price.ethbtc, ethbtc) != 0)
-            return false;
-        if (ethusd_timestamp != null
-                ? !ethusd_timestamp.equals(price.ethusd_timestamp)
-                : price.ethusd_timestamp != null)
-            return false;
-        return (ethbtc_timestamp != null
-                ? !ethbtc_timestamp.equals(price.ethbtc_timestamp)
-                : price.ethbtc_timestamp != null);
+        return Double.compare(price.ethusd, ethusd) == 0 && Double.compare(price.ethbtc, ethbtc) == 0
+                && Objects.equals(ethusd_timestamp, price.ethusd_timestamp)
+                && Objects.equals(ethbtc_timestamp, price.ethbtc_timestamp);
     }
 
     @Override
     public int hashCode() {
-        int result;
-        long temp;
-        temp = Double.doubleToLongBits(ethusd);
-        result = (int) (temp ^ (temp >>> 32));
-        temp = Double.doubleToLongBits(ethbtc);
-        result = 31 * result + (int) (temp ^ (temp >>> 32));
-        result = 31 * result + (ethusd_timestamp != null
-                ? ethusd_timestamp.hashCode()
-                : 0);
-        result = 31 * result + (ethbtc_timestamp != null
-                ? ethbtc_timestamp.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(ethusd, ethbtc, ethusd_timestamp, ethbtc_timestamp);
     }
 
     @Override
@@ -126,11 +107,15 @@ public PriceBuilder withEthBtcTimestamp(LocalDateTime ethbtcTimestamp) {
         public Price build() {
             Price price = new Price();
             price.ethbtc = this.ethbtc;
-            price.ethbtc_timestamp = String.valueOf(this.ethbtcTimestamp.toEpochSecond(ZoneOffset.UTC));
-            price._ethbtc_timestamp = this.ethbtcTimestamp;
             price.ethusd = this.ethusd;
-            price.ethusd_timestamp = String.valueOf(this.ethusdTimestamp.toEpochSecond(ZoneOffset.UTC));
-            price._ethusd_timestamp = this.ethusdTimestamp;
+            if (this.ethbtcTimestamp != null) {
+                price.ethbtc_timestamp = String.valueOf(this.ethbtcTimestamp.toEpochSecond(ZoneOffset.UTC));
+                price._ethbtc_timestamp = this.ethbtcTimestamp;
+            }
+            if (this.ethusdTimestamp != null) {
+                price.ethusd_timestamp = String.valueOf(this.ethusdTimestamp.toEpochSecond(ZoneOffset.UTC));
+                price._ethusd_timestamp = this.ethusdTimestamp;
+            }
             return price;
         }
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 7e09768..3d8cd1f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -228,10 +228,12 @@ public Tx build() {
             tx.value = this.value;
             tx.transactionIndex = this.transactionIndex;
             tx.confirmations = this.confirmations;
-            tx.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timeStamp != null) {
+                tx.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+                tx._timeStamp = this.timeStamp;
+            }
             tx.nonce = this.nonce;
             tx.blockNumber = this.blockNumber;
-            tx._timeStamp = this.timeStamp;
             tx.to = this.to;
             tx.input = this.input;
             tx.cumulativeGasUsed = this.cumulativeGasUsed;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
index edf578f..e6c20f0 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -235,9 +235,11 @@ public TxErc1155 build() {
             txERC721.contractAddress = this.contractAddress;
             txERC721.cumulativeGasUsed = this.cumulativeGasUsed;
             txERC721.tokenID = this.tokenID;
-            txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timeStamp != null) {
+                txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+                txERC721._timeStamp = this.timeStamp;
+            }
             txERC721.blockNumber = this.blockNumber;
-            txERC721._timeStamp = this.timeStamp;
             txERC721.tokenValue = this.tokenValue;
             txERC721.transactionIndex = this.transactionIndex;
             txERC721.to = this.to;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index 9342c8e..197ab5d 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -237,10 +237,12 @@ public TxErc20 build() {
             txERC20.nonce = this.nonce;
             txERC20.confirmations = this.confirmations;
             txERC20.value = this.value;
-            txERC20.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timeStamp != null) {
+                txERC20.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+                txERC20._timeStamp = this.timeStamp;
+            }
             txERC20.blockHash = this.blockHash;
             txERC20.blockNumber = this.blockNumber;
-            txERC20._timeStamp = this.timeStamp;
             txERC20.gasPrice = this.gasPrice;
             txERC20.to = this.to;
             txERC20.input = this.input;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 1276b71..644f738 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -235,9 +235,11 @@ public TxErc721 build() {
             txERC721.contractAddress = this.contractAddress;
             txERC721.cumulativeGasUsed = this.cumulativeGasUsed;
             txERC721.tokenID = this.tokenID;
-            txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timeStamp != null) {
+                txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+                txERC721._timeStamp = this.timeStamp;
+            }
             txERC721.blockNumber = this.blockNumber;
-            txERC721._timeStamp = this.timeStamp;
             txERC721.tokenDecimal = this.tokenDecimal;
             txERC721.transactionIndex = this.transactionIndex;
             txERC721.to = this.to;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index 68bdebf..fdd89ee 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -179,10 +179,12 @@ public TxInternal build() {
             txInternal.from = this.from;
             txInternal.contractAddress = this.contractAddress;
             txInternal.value = this.value;
-            txInternal.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timeStamp != null) {
+                txInternal.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+                txInternal._timeStamp = this.timeStamp;
+            }
             txInternal.errCode = this.errCode;
             txInternal.blockNumber = this.blockNumber;
-            txInternal._timeStamp = this.timeStamp;
             txInternal.isError = this.isError;
             txInternal.to = this.to;
             txInternal.input = this.input;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index e863b7a..2fc2014 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -45,18 +45,15 @@ public BigInteger asEther() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Wei))
             return false;
-
         Wei wei = (Wei) o;
         return Objects.equals(result, wei.result);
     }
 
     @Override
     public int hashCode() {
-        return result != null
-                ? result.hashCode()
-                : 0;
+        return Objects.hash(result);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index 1eb46f3..a9447ca 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -342,26 +342,32 @@ public BlockProxy build() {
             blockProxy.mixHash = this.mixHash;
             blockProxy.totalDifficulty = this.totalDifficulty;
             blockProxy.nonce = this.nonce;
-            blockProxy._gasUsed = this.gasUsed;
             blockProxy.uncles = this.uncles;
             blockProxy.transactionsRoot = this.transactionsRoot;
             blockProxy.number = String.valueOf(this.number);
             blockProxy.logsBloom = this.logsBloom;
             blockProxy.receiptsRoot = this.receiptsRoot;
-            blockProxy._gasLimit = this.gasLimit;
             blockProxy.hash = this.hash;
             blockProxy.parentHash = this.parentHash;
             blockProxy._size = this.size;
-            blockProxy.gasLimit = String.valueOf(this.gasLimit);
             blockProxy.difficulty = this.difficulty;
-            blockProxy.gasUsed = String.valueOf(this.gasUsed);
+            if (this.gasLimit != null) {
+                blockProxy.gasLimit = String.valueOf(this.gasLimit);
+                blockProxy._gasLimit = this.gasLimit;
+            }
+            if (this.gasUsed != null) {
+                blockProxy.gasUsed = String.valueOf(this.gasUsed);
+                blockProxy._gasUsed = this.gasUsed;
+            }
             blockProxy.size = String.valueOf(this.size);
             blockProxy.extraData = this.extraData;
             blockProxy.stateRoot = this.stateRoot;
-            blockProxy._timestamp = this.timestamp;
             blockProxy.sha3Uncles = this.sha3Uncles;
             blockProxy.miner = this.miner;
-            blockProxy.timestamp = String.valueOf(this.timestamp.toEpochSecond(ZoneOffset.UTC));
+            if (this.timestamp != null) {
+                blockProxy.timestamp = String.valueOf(this.timestamp.toEpochSecond(ZoneOffset.UTC));
+                blockProxy._timestamp = this.timestamp;
+            }
             blockProxy.transactions = this.transactions;
             blockProxy._number = this.number;
             return blockProxy;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index a57ce36..61a7942 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -243,14 +243,18 @@ public ReceiptProxy build() {
             receiptProxy.blockHash = this.blockHash;
             receiptProxy.root = this.root;
             receiptProxy.contractAddress = this.contractAddress;
-            receiptProxy.gasUsed = String.valueOf(this.gasUsed);
-            receiptProxy._gasUsed = this.gasUsed;
+            if (this.gasUsed != null) {
+                receiptProxy.gasUsed = String.valueOf(this.gasUsed);
+                receiptProxy._gasUsed = this.gasUsed;
+            }
             receiptProxy.logs = this.logs;
-            receiptProxy.cumulativeGasUsed = String.valueOf(this.cumulativeGasUsed);
             receiptProxy.to = this.to;
+            if (this.cumulativeGasUsed != null) {
+                receiptProxy.cumulativeGasUsed = String.valueOf(this.cumulativeGasUsed);
+                receiptProxy._cumulativeGasUsed = this.cumulativeGasUsed;
+            }
             receiptProxy.transactionIndex = String.valueOf(this.transactionIndex);
             receiptProxy._blockNumber = this.blockNumber;
-            receiptProxy._cumulativeGasUsed = this.cumulativeGasUsed;
             return receiptProxy;
         }
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index b6324e1..0ca7f3a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -262,8 +262,10 @@ public TxProxyBuilder withBlockNumber(Long blockNumber) {
         public TxProxy build() {
             TxProxy txProxy = new TxProxy();
             txProxy.input = this.input;
-            txProxy.gas = String.valueOf(this.gas);
-            txProxy._gas = this.gas;
+            if (this.gas != null) {
+                txProxy.gas = String.valueOf(this.gas);
+                txProxy._gas = this.gas;
+            }
             txProxy.s = this.s;
             txProxy.blockHash = this.blockHash;
             txProxy.to = this.to;
@@ -274,12 +276,14 @@ public TxProxy build() {
             txProxy.v = this.v;
             txProxy.from = this.from;
             txProxy.nonce = String.valueOf(this.nonce);
-            txProxy._gasPrice = this.gasPrice;
             txProxy._transactionIndex = this.transactionIndex;
             txProxy.blockNumber = String.valueOf(this.blockNumber);
             txProxy._blockNumber = this.blockNumber;
             txProxy.hash = this.hash;
-            txProxy.gasPrice = String.valueOf(this.gasPrice);
+            if (this.gasPrice != null) {
+                txProxy.gasPrice = String.valueOf(this.gasPrice);
+                txProxy._gasPrice = this.gasPrice;
+            }
             return txProxy;
         }
     }

From 1beaafdd691fb5ecfb7be0c0c87e9cd0690246df Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 13:13:59 +0300
Subject: [PATCH 31/67] [2.0.0-SNAPSHOT] Balance contract improved Wei contract
 improved Supply constructor added ProxyAPI contract refactored to Wei

---
 .../api/etherscan/GasTrackerAPIProvider.java  |  2 +-
 .../io/goodforgod/api/etherscan/ProxyAPI.java |  8 ++++----
 .../api/etherscan/ProxyAPIProvider.java       | 16 +++++++--------
 .../manager/RequestQueueManager.java          |  4 ++--
 .../api/etherscan/model/Balance.java          | 20 ++-----------------
 .../api/etherscan/model/Supply.java           |  4 ++++
 .../goodforgod/api/etherscan/model/Wei.java   |  2 +-
 .../account/AccountBalanceListTests.java      | 10 +++-------
 .../api/etherscan/proxy/ProxyGasApiTests.java | 14 ++++++-------
 .../statistic/StatisticSupplyApiTests.java    |  2 +-
 10 files changed, 33 insertions(+), 49 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
index a4db5ae..0b559d8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
@@ -34,7 +34,7 @@ final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI
 
     @Override
     public @NotNull GasEstimate estimate(@NotNull Wei wei) throws EtherScanException {
-        final String urlParams = ACT_GAS_ESTIMATE_PARAM + GASPRICE_PARAM + wei.getValue().toString();
+        final String urlParams = ACT_GAS_ESTIMATE_PARAM + GASPRICE_PARAM + wei.asWei().toString();
         final GasEstimateResponseTO response = getRequest(urlParams, GasEstimateResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
index 0785d13..b379290 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
@@ -1,10 +1,10 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
 import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
 import io.goodforgod.api.etherscan.model.proxy.TxProxy;
-import java.math.BigInteger;
 import java.util.Optional;
 import org.jetbrains.annotations.ApiStatus.Experimental;
 import org.jetbrains.annotations.NotNull;
@@ -150,7 +150,7 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    BigInteger gasPrice() throws EtherScanException;
+    Wei gasPrice() throws EtherScanException;
 
     /**
      * Makes a call or transaction, which won't be added to the blockchain and returns the used gas,
@@ -161,8 +161,8 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    BigInteger gasEstimated(String hexData) throws EtherScanException;
+    Wei gasEstimated(String hexData) throws EtherScanException;
 
     @NotNull
-    BigInteger gasEstimated() throws EtherScanException;
+    Wei gasEstimated() throws EtherScanException;
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index a306541..27e00df 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -5,6 +5,7 @@
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
 import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
 import io.goodforgod.api.etherscan.model.proxy.TxProxy;
@@ -13,7 +14,6 @@
 import io.goodforgod.api.etherscan.model.proxy.utility.TxInfoProxyTO;
 import io.goodforgod.api.etherscan.model.proxy.utility.TxProxyTO;
 import io.goodforgod.api.etherscan.util.BasicUtils;
-import java.math.BigInteger;
 import java.util.Optional;
 import java.util.regex.Pattern;
 import org.jetbrains.annotations.NotNull;
@@ -197,29 +197,29 @@ public Optional<String> storageAt(String address, long position) throws EtherSca
 
     @NotNull
     @Override
-    public BigInteger gasPrice() throws EtherScanException {
+    public Wei gasPrice() throws EtherScanException {
         final StringProxyTO response = getRequest(ACT_GASPRICE_PARAM, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
-                ? BigInteger.valueOf(-1)
-                : BasicUtils.parseHex(response.getResult());
+                ? new Wei(0)
+                : new Wei(BasicUtils.parseHex(response.getResult()));
     }
 
     @NotNull
     @Override
-    public BigInteger gasEstimated() throws EtherScanException {
+    public Wei gasEstimated() throws EtherScanException {
         return gasEstimated("606060405260728060106000396000f360606040526000");
     }
 
     @NotNull
     @Override
-    public BigInteger gasEstimated(String hexData) throws EtherScanException {
+    public Wei gasEstimated(String hexData) throws EtherScanException {
         if (!BasicUtils.isEmpty(hexData) && BasicUtils.isNotHex(hexData))
             throw new EtherScanInvalidDataHexException("Data is not in hex format.");
 
         final String urlParams = ACT_ESTIMATEGAS_PARAM + DATA_PARAM + hexData + GAS_PARAM + "2000000000000000";
         final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
-                ? BigInteger.valueOf(-1)
-                : BasicUtils.parseHex(response.getResult());
+                ? new Wei(0)
+                : new Wei(BasicUtils.parseHex(response.getResult()));
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index f19603f..46a76e2 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -16,13 +16,13 @@ public interface RequestQueueManager extends AutoCloseable {
     /**
      * Is used by default when no API KEY is provided
      */
-    RequestQueueManager ANONYMOUS = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5005L));
+    RequestQueueManager ANONYMOUS = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5010L));
 
     /**
      * Is available for all registered free API KEYs
      * <a href="https://docs.etherscan.io/getting-started/viewing-api-usage-statistics">Free API KEY</a>
      */
-    RequestQueueManager FREE_PLAN = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1005L));
+    RequestQueueManager FREE_PLAN = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1010L));
 
     RequestQueueManager UNLIMITED = new FakeRequestQueueManager();
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
index 4de8a54..783b7d8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
@@ -23,24 +23,8 @@ public String getAddress() {
         return address;
     }
 
-    public BigInteger getWei() {
-        return balance.getValue();
-    }
-
-    public BigInteger getKwei() {
-        return balance.asKwei();
-    }
-
-    public BigInteger getMwei() {
-        return balance.asMwei();
-    }
-
-    public BigInteger getGwei() {
-        return balance.asGwei();
-    }
-
-    public BigInteger getEther() {
-        return balance.asEther();
+    public Wei getBalanceInWei() {
+        return balance;
     }
     // </editor-fold>
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Supply.java b/src/main/java/io/goodforgod/api/etherscan/model/Supply.java
index 80dc7d0..43e3a3f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Supply.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Supply.java
@@ -8,6 +8,10 @@
  */
 public class Supply extends Wei {
 
+    public Supply(long value) {
+        super(value);
+    }
+
     public Supply(BigInteger value) {
         super(value);
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index 2fc2014..cb136df 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -20,7 +20,7 @@ public Wei(BigInteger value) {
     }
 
     // <editor-fold desc="Getters">
-    public BigInteger getValue() {
+    public BigInteger asWei() {
         return result;
     }
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTests.java
index f611b62..0054a84 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceListTests.java
@@ -29,13 +29,9 @@ void correct() {
         assertNotEquals(balances.get(0).hashCode(), balances.get(1).hashCode());
         for (Balance balance : balances) {
             assertNotNull(balance.getAddress());
-            assertNotNull(balance.getGwei());
-            assertNotNull(balance.getKwei());
-            assertNotNull(balance.getMwei());
-            assertNotNull(balance.getEther());
-            assertNotNull(balance.getGwei());
+            assertNotNull(balance.getBalanceInWei());
             assertNotNull(balance.getAddress());
-            assertNotEquals(BigInteger.ZERO, balance.getWei());
+            assertNotEquals(BigInteger.ZERO, balance.getBalanceInWei().asWei());
             assertNotNull(balance.toString());
         }
     }
@@ -84,7 +80,7 @@ void correctParamWithEmptyExpectedResult() {
         assertEquals(2, balances.size());
         for (Balance balance : balances) {
             assertNotNull(balance.getAddress());
-            assertEquals(0, balance.getWei().intValue());
+            assertEquals(0, balance.getBalanceInWei().asWei().intValue());
         }
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTests.java
index 0ab2a77..4dea82e 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyGasApiTests.java
@@ -2,7 +2,7 @@
 
 import io.goodforgod.api.etherscan.ApiRunner;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidDataHexException;
-import java.math.BigInteger;
+import io.goodforgod.api.etherscan.model.Wei;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -13,23 +13,23 @@ class ProxyGasApiTests extends ApiRunner {
 
     @Test
     void correctPrice() {
-        BigInteger price = getApi().proxy().gasPrice();
+        Wei price = getApi().proxy().gasPrice();
         assertNotNull(price);
-        assertNotEquals(0, price.intValue());
+        assertNotEquals(0, price.asWei().intValue());
     }
 
     @Test
     void correctEstimated() {
-        BigInteger price = getApi().proxy().gasEstimated();
+        Wei price = getApi().proxy().gasEstimated();
         assertNotNull(price);
-        assertNotEquals(0, price.intValue());
+        assertNotEquals(0, price.asWei().intValue());
     }
 
     @Test
     void correctEstimatedWithData() {
         String dataCustom = "606060405260728060106000396000f360606040526000606060405260728060106000396000f360606040526000";
-        BigInteger price = getApi().proxy().gasEstimated();
-        BigInteger priceCustom = getApi().proxy().gasEstimated(dataCustom);
+        Wei price = getApi().proxy().gasEstimated();
+        Wei priceCustom = getApi().proxy().gasEstimated(dataCustom);
         assertNotNull(price);
         assertNotNull(priceCustom);
         assertNotEquals(price, priceCustom);
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
index fa79028..56469a9 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
@@ -15,7 +15,7 @@ class StatisticSupplyApiTests extends ApiRunner {
     void correct() {
         Supply supply = getApi().stats().supply();
         assertNotNull(supply);
-        assertNotNull(supply.getValue());
+        assertNotNull(supply.asWei());
         assertNotNull(supply.asGwei());
         assertNotNull(supply.asKwei());
         assertNotNull(supply.asMwei());

From 948a6f3e7cd5b7aa0d6121c113035321dd059663 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 21:15:56 +0300
Subject: [PATCH 32/67] [2.0.0-SNAPSHOT] README.md updated Balance &
 TokenBalance constructor improved

---
 README.md                                     | 111 +++++++++---------
 .../api/etherscan/AccountAPIProvider.java     |   6 +-
 .../api/etherscan/EtherScanAPI.java           |   5 +
 .../api/etherscan/model/Balance.java          |   5 +-
 .../api/etherscan/model/TokenBalance.java     |   3 +-
 .../account/AccountBalanceTests.java          |  10 +-
 .../account/AccountTokenBalanceTests.java     |   8 +-
 7 files changed, 73 insertions(+), 75 deletions(-)

diff --git a/README.md b/README.md
index cd981ca..4cff68d 100644
--- a/README.md
+++ b/README.md
@@ -43,82 +43,84 @@ implementation "com.github.goodforgod:java-etherscan-api:2.0.0-SNAPSHOT"
 
 ## Mainnet and Testnets
 
-API support Ethereum: *[MAINNET](https://etherscan.io),
- [ROPSTEN](https://ropsten.etherscan.io), 
- [KOVAN](https://kovan.etherscan.io), 
- [RINKEBY](https://rinkeby.etherscan.io), 
- [GORLI](https://goerli.etherscan.io), 
- [TOBALABA](https://tobalaba.etherscan.com)* networks.
+API support Ethereum [default networks](https://docs.etherscan.io/getting-started/endpoint-urls):
+- [Mainnet](https://api.etherscan.io/)
+- [Goerli](https://api-goerli.etherscan.io/)
+- [Sepolia](https://api-sepolia.etherscan.io/)
+
 ```java
-EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET); // Default
-EtherScanApi apiRinkeby = new EtherScanApi(EthNetwork.RINKEBY);
-EtherScanApi apiRopsten = new EtherScanApi(EthNetwork.ROPSTEN);
-EtherScanApi apiKovan = new EtherScanApi("YourApiKey", EthNetwork.KOVAN);
+EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI apiGoerli = EtherScanAPI.builder().withNetwork(EthNetworks.GORLI).build();
+EtherScanAPI apiSepolia = EtherScanAPI.builder().withNetwork(EthNetworks.SEPOLIA).build();
+```
+
+### Custom Network
+
+In case you want to use API for other EtherScan compatible network, you can easily provide custom network with domain api URI.
+
+```java
+EtherScanAPI api = EtherScanAPI.builder()
+        .withNetwork(() -> URI.create("https://api-my-custom.etherscan.io/api"))
+        .build();
 ```
 
 ## Custom HttpClient
 
 In case you need to set custom timeout, custom headers or better implementation for HttpClient, 
-just implement **IHttpExecutor** by your self or initialize it with your values.
+just implement **EthHttpClient** by your self or initialize it with your values.
 
 ```java
-int connectionTimeout = 10000;
-int readTimeout = 7000;
- 
-Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(connectionTimeout);
-Supplier<IHttpExecutor> supplierFull = () -> new HttpExecutor(connectionTimeout, readTimeout);
- 
-EtherScanApi api = new EtherScanApi(EthNetwork.RINKEBY, supplier);
-EtherScanApi apiWithKey = new EtherScanApi("YourApiKey", EthNetwork.MAINNET, supplierFull);
+Supplier<EthHttpClient> ethHttpClientSupplier = () -> new UrlEthHttpClient(Duration.ofMillis(300), Duration.ofMillis(300));
+EtherScanAPI api = EtherScanAPI.builder()
+    .withHttpClient(supplier)
+    .build();
 ```
 
 ## API Examples
 
-You can read about all API methods on [Etherscan](https://etherscan.io/apis)
+You can read about all API methods on [Etherscan](https://docs.etherscan.io/api-endpoints/accounts)
 
 *Library support all available EtherScan API.*
 
-You can use library *with or without* API key *([Check API request\sec restrictions when used without API key](https://ethereum.stackexchange.com/questions/34190/does-etherscan-require-the-use-of-an-api-key))*.
+You can use library *with or without* API key *([Check API request\sec restrictions when used without API key](https://docs.etherscan.io/getting-started/viewing-api-usage-statistics))*.
 
-Library will automatically limit requests up to **5 req/sec** when used *without* key.
+Library will automatically limit requests up to **1 requests in 5 seconds** when used *without* key and up to **5 requests in 1 seconds** when used with API KEY (free plan).
 ```java
-EtherScanApi api = new EtherScanApi();
-EtherScanApi api = new EtherScanApi("YourApiKey");
+EtherScanAPI.builder()
+        .withApiKey(ApiRunner.API_KEY)
+        .build();
 ```
 
 Below are examples for each API category.
 
-### Account Api
+### Account API
 
 **Get Ether Balance for a single Address**
-
 ```java
-EtherScanApi api = new EtherScanApi();
+EtherScanAPI api = EtherScanAPI.build();
 Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
 ```
 
-### Block Api
+### Block API
 
 **Get uncles block for block height**
-
 ```java
-EtherScanApi api = new EtherScanApi();
+EtherScanAPI api = EtherScanAPI.build();
 Optional<UncleBlock> uncles = api.block().uncles(200000);
 ```
 
-### Contract Api
+### Contract API
 **Request contract ABI from [verified codes](https://etherscan.io/contractsVerified)**
 ```java
-EtherScanApi api = new EtherScanApi();
+EtherScanAPI api = EtherScanAPI.build();
 Abi abi = api.contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413");
 ```
 
-### Logs Api
+### Logs API
 
 **Get event logs for single topic**
-
 ```java
-EtherScanApi api = new EtherScanApi();
+EtherScanAPI api = EtherScanAPI.build();
 LogQuery query = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
            .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
            .build();
@@ -126,58 +128,55 @@ List<Log> logs = api.logs().logs(query);
 ```
 
 **Get event logs for 3 topics with respectful operations**
-
 ```java
-EtherScanApi api = new EtherScanApi();
-LogQuery query = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
-        .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
-                "0x72657075746174696f6e00000000000000000000000000000000000000000000",
-                "0x72657075746174696f6e00000000000000000000000000000000000000000000")
+EtherScanAPI api = EtherScanAPI.build();
+LogQuery query = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+        .withBlockFrom(379224)
+        .withBlockTo(400000)
+        .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
+        "0x72657075746174696f6e00000000000000000000000000000000000000000000",
+        "0x72657075746174696f6e00000000000000000000000000000000000000000000")
         .setOpTopic0_1(LogOp.AND)
-        .setOpTopic0_2(LogOp.OR)
+        .setOpTopic0_2(null)
         .setOpTopic1_2(LogOp.AND)
         .build();
  
 List<Log> logs = api.logs().logs(query);
 ```
 
-### Proxy Api
-
-**Get tx detailds with proxy endpoint**
+### Proxy API
 
+**Get tx details with proxy endpoint**
 ```java
-EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
+EtherScanAPI api = EtherScanAPI.build();
 Optional<TxProxy> tx = api.proxy().tx("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
 ```
 
 **Get block info with proxy endpoint**
-
 ```java
-EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
+EtherScanAPI api = EtherScanAPI.build();
 Optional<BlockProxy> block = api.proxy().block(15215);
 ```
 
-### Stats Api
+### Stats API
 
 **Statistic about last price**
-
 ```java
-EtherScanApi api = new EtherScanApi();
+EtherScanAPI api = EtherScanAPI.build();
 Price price = api.stats().lastPrice();
 ```
 
-### Transaction Api
+### Transaction API
 
 **Request receipt status for tx**
-
 ```java
-EtherScanApi api = new EtherScanApi();
+EtherScanAPI api = EtherScanAPI.build();
 Optional<Boolean> status = api.txs().receiptStatus("0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
 ```
 
-### Token Api
+### Token API
 
-You can read about token API [here](https://etherscan.io/apis#tokens)
+You can read about token API [here](https://docs.etherscan.io/api-endpoints/tokens)
 
 Token API methods migrated to [Account](#account-api) & [Stats](#stats-api) respectfully.
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 1b7bce6..11bb192 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -64,7 +64,7 @@ public Balance balance(String address) throws EtherScanException {
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
-        return new Balance(address, new BigInteger(response.getResult()));
+        return new Balance(address, new Wei(new BigInteger(response.getResult())));
     }
 
     @NotNull
@@ -78,7 +78,7 @@ public TokenBalance balance(String address, String contract) throws EtherScanExc
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
-        return new TokenBalance(address, new BigInteger(response.getResult()), contract);
+        return new TokenBalance(address, new Wei(new BigInteger(response.getResult())), contract);
     }
 
     @NotNull
@@ -101,7 +101,7 @@ public List<Balance> balances(List<String> addresses) throws EtherScanException
 
             if (!BasicUtils.isEmpty(response.getResult()))
                 balances.addAll(response.getResult().stream()
-                        .map(r -> new Balance(r.getAccount(), new BigInteger(r.getBalance())))
+                        .map(r -> new Balance(r.getAccount(), new Wei(new BigInteger(r.getBalance()))))
                         .collect(Collectors.toList()));
         }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
index 6da3d8f..dffb1aa 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -37,6 +37,11 @@ public interface EtherScanAPI extends AutoCloseable {
     @NotNull
     GasTrackerAPI gasTracker();
 
+    @NotNull
+    static EtherScanAPI build() {
+        return builder().build();
+    }
+
     @NotNull
     static Builder builder() {
         return new EthScanAPIBuilder();
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
index 783b7d8..079d4b6 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
@@ -1,6 +1,5 @@
 package io.goodforgod.api.etherscan.model;
 
-import java.math.BigInteger;
 import java.util.Objects;
 
 /**
@@ -13,9 +12,9 @@ public class Balance {
     private final Wei balance;
     private final String address;
 
-    public Balance(String address, BigInteger balance) {
+    public Balance(String address, Wei balance) {
         this.address = address;
-        this.balance = new Wei(balance);
+        this.balance = balance;
     }
 
     // <editor-fold desc="Getters">
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
index d42fd05..0c1a5b5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
@@ -1,6 +1,5 @@
 package io.goodforgod.api.etherscan.model;
 
-import java.math.BigInteger;
 import java.util.Objects;
 
 /**
@@ -11,7 +10,7 @@ public class TokenBalance extends Balance {
 
     private final String tokenContract;
 
-    public TokenBalance(String address, BigInteger balance, String tokenContract) {
+    public TokenBalance(String address, Wei balance, String tokenContract) {
         super(address, balance);
         this.tokenContract = tokenContract;
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTests.java
index f22a724..ed537c6 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountBalanceTests.java
@@ -18,11 +18,7 @@ class AccountBalanceTests extends ApiRunner {
     void correct() {
         Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
         assertNotNull(balance);
-        assertNotNull(balance.getWei());
-        assertNotNull(balance.getMwei());
-        assertNotNull(balance.getKwei());
-        assertNotNull(balance.getGwei());
-        assertNotNull(balance.getEther());
+        assertNotNull(balance.getBalanceInWei());
         assertNotNull(balance.getAddress());
         assertNotNull(balance.toString());
     }
@@ -37,8 +33,8 @@ void invalidParamWithError() {
     void correctParamWithEmptyExpectedResult() {
         Balance balance = api.account().balance("0x1d4426f94e42f721C7116E81d6688cd935cB3b4F");
         assertNotNull(balance);
-        assertNotNull(balance.getWei());
+        assertNotNull(balance.getBalanceInWei());
         assertNotNull(balance.getAddress());
-        assertEquals(0, balance.getWei().intValue());
+        assertEquals(0, balance.getBalanceInWei().asWei().intValue());
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTests.java
index 4a7d921..3919982 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTokenBalanceTests.java
@@ -19,12 +19,12 @@ void correct() {
         TokenBalance balance = api.account().balance("0x5d807e7F124EC2103a59c5249187f772c0b8D6b2",
                 "0x5EaC95ad5b287cF44E058dCf694419333b796123");
         assertNotNull(balance);
-        assertNotNull(balance.getWei());
+        assertNotNull(balance.getBalanceInWei());
         assertNotNull(balance.getAddress());
         assertNotNull(balance.getContract());
         assertNotNull(balance.toString());
 
-        TokenBalance balance2 = new TokenBalance("125161", balance.getWei(), balance.getContract());
+        TokenBalance balance2 = new TokenBalance("125161", balance.getBalanceInWei(), balance.getContract());
         assertNotEquals(balance, balance2);
         assertNotEquals(balance.hashCode(), balance2.hashCode());
     }
@@ -48,9 +48,9 @@ void correctParamWithEmptyExpectedResult() {
         TokenBalance balance = api.account().balance("0x1d807e7F124EC2103a59c5249187f772c0b8D6b2",
                 "0x5EaC95ad5b287cF44E058dCf694419333b796123");
         assertNotNull(balance);
-        assertNotNull(balance.getWei());
+        assertNotNull(balance.getBalanceInWei());
         assertNotNull(balance.getAddress());
         assertNotNull(balance.getContract());
-        assertEquals(0, balance.getWei().intValue());
+        assertEquals(0, balance.getBalanceInWei().asWei().intValue());
     }
 }

From 3210c397fa652629f1ff0ba7cc7e198b26879976 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 21:39:08 +0300
Subject: [PATCH 33/67] [2.0.0-SNAPSHOT] EthHttpClient contract refactored to
 response with byte[] Converter contract refactored to receive byte[]

---
 .../api/etherscan/BasicProvider.java          | 16 +++----
 .../api/etherscan/BlockAPIProvider.java       |  8 +++-
 .../api/etherscan/ContractAPIProvider.java    |  3 +-
 .../goodforgod/api/etherscan/Converter.java   |  2 +-
 .../api/etherscan/EthScanAPIBuilder.java      |  6 ++-
 .../api/etherscan/http/EthHttpClient.java     |  6 +--
 .../etherscan/http/impl/UrlEthHttpClient.java | 42 +++++++++----------
 .../manager/RequestQueueManager.java          |  7 +++-
 .../goodforgod/api/etherscan/model/Wei.java   |  4 ++
 .../etherscan/model/ModelBuilderTests.java    |  1 +
 10 files changed, 54 insertions(+), 41 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index f1867d1..998f475 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -7,7 +7,6 @@
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
-import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
@@ -44,7 +43,7 @@ abstract class BasicProvider {
         this.converter = converter;
     }
 
-    <T> T convert(String json, Class<T> tClass) {
+    <T> T convert(byte[] json, Class<T> tClass) {
         try {
             final T t = converter.fromJson(json, tClass);
             if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith("Max rate limit reached")) {
@@ -53,32 +52,33 @@ <T> T convert(String json, Class<T> tClass) {
 
             return t;
         } catch (Exception e) {
+            final String jsonAsString = new String(json, StandardCharsets.UTF_8);
             try {
                 final Map<String, Object> map = converter.fromJson(json, Map.class);
                 final Object result = map.get("result");
                 if (result instanceof String && ((String) result).startsWith("Max rate limit reached"))
                     throw new EtherScanRateLimitException(((String) result));
 
-                throw new EtherScanParseException(e.getMessage() + ", for response: " + json, e.getCause(), json);
+                throw new EtherScanParseException(e.getMessage() + ", for response: " + jsonAsString, e.getCause(), jsonAsString);
             } catch (EtherScanException ex) {
                 throw ex;
             } catch (Exception ex) {
-                throw new EtherScanParseException(e.getMessage() + ", for response: " + json, e.getCause(), json);
+                throw new EtherScanParseException(e.getMessage() + ", for response: " + jsonAsString, e.getCause(), jsonAsString);
             }
         }
     }
 
-    String getRequest(String urlParameters) {
+    byte[] getRequest(String urlParameters) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
-        final String result = executor.get(uri);
-        if (BasicUtils.isEmpty(result))
+        final byte[] result = executor.get(uri);
+        if (result.length == 0)
             throw new EtherScanResponseException("Server returned null value for GET request at URL - " + uri);
 
         return result;
     }
 
-    String postRequest(String urlParameters, String dataToPost) {
+    byte[] postRequest(String urlParameters, String dataToPost) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
         return executor.post(uri, dataToPost.getBytes(StandardCharsets.UTF_8));
diff --git a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
index 98a2d90..41d86dd 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
@@ -33,11 +33,15 @@ final class BlockAPIProvider extends BasicProvider implements BlockAPI {
     @Override
     public Optional<BlockUncle> uncles(long blockNumber) throws EtherScanException {
         final String urlParam = ACT_BLOCK_PARAM + BLOCKNO_PARAM + blockNumber;
-        final String response = getRequest(urlParam);
-        if (BasicUtils.isEmpty(response) || response.contains("NOTOK"))
+        final byte[] response = getRequest(urlParam);
+        if (response.length == 0)
             return Optional.empty();
 
         final UncleBlockResponseTO responseTO = convert(response, UncleBlockResponseTO.class);
+        if (responseTO.getMessage().equals("NOTOK")) {
+            return Optional.empty();
+        }
+
         BasicUtils.validateTxResponse(responseTO);
         return (responseTO.getResult() == null || responseTO.getResult().isEmpty())
                 ? Optional.empty()
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index 1a8fa9a..7b75240 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -36,8 +36,9 @@ public Abi contractAbi(String address) throws EtherScanException {
 
         final String urlParam = ACT_ABI_PARAM + ADDRESS_PARAM + address;
         final StringResponseTO response = getRequest(urlParam, StringResponseTO.class);
-        if (response.getStatus() != 1 && "NOTOK".equals(response.getMessage()))
+        if (response.getStatus() != 1 && "NOTOK".equals(response.getMessage())) {
             throw new EtherScanResponseException(response);
+        }
 
         return (response.getResult().startsWith("Contract sou"))
                 ? Abi.nonVerified()
diff --git a/src/main/java/io/goodforgod/api/etherscan/Converter.java b/src/main/java/io/goodforgod/api/etherscan/Converter.java
index e8c577a..4025839 100644
--- a/src/main/java/io/goodforgod/api/etherscan/Converter.java
+++ b/src/main/java/io/goodforgod/api/etherscan/Converter.java
@@ -9,5 +9,5 @@
 public interface Converter {
 
     @NotNull
-    <T> T fromJson(@NotNull String json, @NotNull Class<T> type);
+    <T> T fromJson(byte[] jsonAsByteArray, @NotNull Class<T> type);
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index c9c1102..69474d9 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -7,6 +7,7 @@
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import io.goodforgod.gson.configuration.GsonConfiguration;
+import java.nio.charset.StandardCharsets;
 import java.util.function.Supplier;
 import org.jetbrains.annotations.NotNull;
 
@@ -28,8 +29,9 @@ final class EthScanAPIBuilder implements EtherScanAPI.Builder {
     private Supplier<Converter> converterSupplier = () -> new Converter() {
 
         @Override
-        public <T> @NotNull T fromJson(@NotNull String json, @NotNull Class<T> type) {
-            return gson.fromJson(json, type);
+        public <T> @NotNull T fromJson(byte[] jsonAsByteArray, @NotNull Class<T> type) {
+            final String jsonAsString = new String(jsonAsByteArray, StandardCharsets.UTF_8);
+            return gson.fromJson(jsonAsString, type);
         }
     };
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
index f4b559d..bd01f83 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
@@ -17,8 +17,7 @@ public interface EthHttpClient {
      * @param uri as string
      * @return result as string
      */
-    @NotNull
-    String get(@NotNull URI uri);
+    byte[] get(@NotNull URI uri);
 
     /**
      * Performs a Http POST request
@@ -27,6 +26,5 @@ public interface EthHttpClient {
      * @param body to post
      * @return result as string
      */
-    @NotNull
-    String post(@NotNull URI uri, byte[] body);
+    byte[] post(@NotNull URI uri, byte[] body);
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
index 57c970b..b298743 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
@@ -5,15 +5,11 @@
 import io.goodforgod.api.etherscan.error.EtherScanConnectionException;
 import io.goodforgod.api.etherscan.error.EtherScanTimeoutException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
+import java.io.*;
 import java.net.HttpURLConnection;
 import java.net.SocketTimeoutException;
 import java.net.URI;
 import java.net.URL;
-import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 import java.util.Collections;
 import java.util.HashMap;
@@ -83,7 +79,7 @@ private HttpURLConnection buildConnection(URI uri, String method) throws IOExcep
     }
 
     @Override
-    public @NotNull String get(@NotNull URI uri) {
+    public byte[] get(@NotNull URI uri) {
         try {
             final HttpURLConnection connection = buildConnection(uri, "GET");
             final int status = connection.getResponseCode();
@@ -95,7 +91,7 @@ private HttpURLConnection buildConnection(URI uri, String method) throws IOExcep
                 throw new EtherScanConnectionException("Server error: " + connection.getResponseMessage());
             }
 
-            final String data = readData(connection);
+            final byte[] data = readData(connection);
             connection.disconnect();
             return data;
         } catch (SocketTimeoutException e) {
@@ -106,7 +102,7 @@ private HttpURLConnection buildConnection(URI uri, String method) throws IOExcep
     }
 
     @Override
-    public @NotNull String post(@NotNull URI uri, byte[] body) {
+    public byte[] post(@NotNull URI uri, byte[] body) {
         try {
             final HttpURLConnection connection = buildConnection(uri, "POST");
             final int contentLength = body.length;
@@ -129,7 +125,7 @@ private HttpURLConnection buildConnection(URI uri, String method) throws IOExcep
                 throw new EtherScanConnectionException("Server error: " + connection.getResponseMessage());
             }
 
-            final String data = readData(connection);
+            final byte[] data = readData(connection);
             connection.disconnect();
             return data;
         } catch (SocketTimeoutException e) {
@@ -139,25 +135,29 @@ private HttpURLConnection buildConnection(URI uri, String method) throws IOExcep
         }
     }
 
-    private String readData(HttpURLConnection connection) throws IOException {
-        final StringBuilder content = new StringBuilder();
-        try (BufferedReader in = new BufferedReader(getStreamReader(connection))) {
-            String inputLine;
-            while ((inputLine = in.readLine()) != null)
-                content.append(inputLine);
-        }
+    private byte[] readData(HttpURLConnection connection) throws IOException {
+        try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
+            try (InputStream in = getStreamReader(connection)) {
+                byte[] data = new byte[256];
+                int nRead;
+                while ((nRead = in.read(data, 0, data.length)) != -1) {
+                    buffer.write(data, 0, nRead);
+                }
+            }
 
-        return content.toString();
+            buffer.flush();
+            return buffer.toByteArray();
+        }
     }
 
-    private InputStreamReader getStreamReader(HttpURLConnection connection) throws IOException {
+    private InputStream getStreamReader(HttpURLConnection connection) throws IOException {
         switch (String.valueOf(connection.getContentEncoding())) {
             case "gzip":
-                return new InputStreamReader(new GZIPInputStream(connection.getInputStream()), StandardCharsets.UTF_8);
+                return new GZIPInputStream(connection.getInputStream());
             case "deflate":
-                return new InputStreamReader(new InflaterInputStream(connection.getInputStream()), StandardCharsets.UTF_8);
+                return new InflaterInputStream(connection.getInputStream());
             default:
-                return new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8);
+                return connection.getInputStream();
         }
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index 46a76e2..2fdfe82 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -5,8 +5,8 @@
 import java.time.Duration;
 
 /**
- * Queue manager to support API limits (EtherScan 5request\sec limit) Managers grants turn if the
- * limit is not exhausted And resets queue each set period
+ * Queue manager to support API limits
+ * Manager grants turn if the limit is not exhausted And resets queue each set period
  *
  * @author GoodforGod
  * @since 30.10.2018
@@ -23,6 +23,9 @@ public interface RequestQueueManager extends AutoCloseable {
      * <a href="https://docs.etherscan.io/getting-started/viewing-api-usage-statistics">Free API KEY</a>
      */
     RequestQueueManager FREE_PLAN = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1010L));
+    RequestQueueManager STANDARD_PLAN = new SemaphoreRequestQueueManager(10, Duration.ofMillis(1010L));
+    RequestQueueManager ADVANCED_PLAN = new SemaphoreRequestQueueManager(20, Duration.ofMillis(1010L));
+    RequestQueueManager PROFESSIONAL_PLAN = new SemaphoreRequestQueueManager(30, Duration.ofMillis(1010L));
 
     RequestQueueManager UNLIMITED = new FakeRequestQueueManager();
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index cb136df..e23ea51 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -11,6 +11,10 @@ public class Wei {
 
     private final BigInteger result;
 
+    public Wei(int value) {
+        this.result = BigInteger.valueOf(value);
+    }
+
     public Wei(long value) {
         this.result = BigInteger.valueOf(value);
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index 7db6aae..1bec491 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -252,6 +252,7 @@ void txInternalBuilder() {
                 .withContractAddress("1")
                 .withFrom("1")
                 .withTo("1")
+                .withValue(BigInteger.ONE)
                 .withGas(BigInteger.ONE)
                 .withGasUsed(BigInteger.ONE)
                 .withHash("1")

From f5b2edb7db033600bc7e54b4c60836306554c5a6 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 22:06:44 +0300
Subject: [PATCH 34/67] [2.0.0-SNAPSHOT] EtherScanLogQueryException name fixed
 EtherScanResponseException response entity added StringResponseTO#builder
 added BasicProvider error handling improved

---
 .../api/etherscan/BasicProvider.java          | 26 +++++++++++---
 .../api/etherscan/BlockAPIProvider.java       | 30 ++++++++++------
 .../api/etherscan/ContractAPIProvider.java    |  2 +-
 .../api/etherscan/EtherScanAPI.java           |  5 ---
 .../api/etherscan/ProxyAPIProvider.java       | 12 +++++--
 ...n.java => EtherScanLogQueryException.java} |  4 +--
 .../error/EtherScanResponseException.java     | 14 ++++++--
 .../model/query/LogQueryBuilderImpl.java      | 24 ++++++-------
 .../etherscan/model/query/LogTopicQuadro.java | 14 ++++----
 .../etherscan/model/query/LogTopicSingle.java |  4 +--
 .../etherscan/model/query/LogTopicTriple.java | 10 +++---
 .../etherscan/model/query/LogTopicTuple.java  |  6 ++--
 .../model/response/BaseResponseTO.java        |  4 +--
 .../model/response/StringResponseTO.java      | 36 +++++++++++++++++++
 .../api/etherscan/util/BasicUtils.java        | 12 +++++--
 .../etherscan/logs/LogQueryBuilderTests.java  | 36 +++++++++----------
 16 files changed, 160 insertions(+), 79 deletions(-)
 rename src/main/java/io/goodforgod/api/etherscan/error/{ErtherScanLogQueryException.java => EtherScanLogQueryException.java} (50%)

diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 998f475..3c88f3b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -20,6 +20,8 @@
  */
 abstract class BasicProvider {
 
+    private static final String MAX_RATE_LIMIT_REACHED = "Max rate limit reached";
+
     static final int MAX_END_BLOCK = Integer.MAX_VALUE;
     static final int MIN_START_BLOCK = 0;
 
@@ -46,17 +48,26 @@ abstract class BasicProvider {
     <T> T convert(byte[] json, Class<T> tClass) {
         try {
             final T t = converter.fromJson(json, tClass);
-            if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith("Max rate limit reached")) {
+            if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith(MAX_RATE_LIMIT_REACHED)) {
                 throw new EtherScanRateLimitException(((StringResponseTO) t).getResult());
             }
 
             return t;
         } catch (Exception e) {
+            final StringResponseTO response = converter.fromJson(json, StringResponseTO.class);
+            if (response.getResult() != null && response.getStatus() == 0) {
+                if (response.getResult().startsWith(MAX_RATE_LIMIT_REACHED)) {
+                    throw new EtherScanRateLimitException(response.getResult());
+                } else {
+                    throw new EtherScanResponseException(response);
+                }
+            }
+
             final String jsonAsString = new String(json, StandardCharsets.UTF_8);
             try {
                 final Map<String, Object> map = converter.fromJson(json, Map.class);
                 final Object result = map.get("result");
-                if (result instanceof String && ((String) result).startsWith("Max rate limit reached"))
+                if (result instanceof String && ((String) result).startsWith(MAX_RATE_LIMIT_REACHED))
                     throw new EtherScanRateLimitException(((String) result));
 
                 throw new EtherScanParseException(e.getMessage() + ", for response: " + jsonAsString, e.getCause(), jsonAsString);
@@ -72,8 +83,15 @@ byte[] getRequest(String urlParameters) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
         final byte[] result = executor.get(uri);
-        if (result.length == 0)
-            throw new EtherScanResponseException("Server returned null value for GET request at URL - " + uri);
+        if (result.length == 0) {
+            final StringResponseTO emptyResponse = StringResponseTO.builder()
+                    .withStatus("0")
+                    .withMessage("Server returned null value for GET request at URL - " + uri)
+                    .withResult("")
+                    .build();
+
+            throw new EtherScanResponseException(emptyResponse, "Server returned null value for GET request at URL - " + uri);
+        }
 
         return result;
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
index 41d86dd..406ac19 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.BlockUncle;
@@ -12,8 +13,8 @@
 /**
  * Block API Implementation
  *
- * @see BlockAPI
  * @author GoodforGod
+ * @see BlockAPI
  * @since 28.10.2018
  */
 final class BlockAPIProvider extends BasicProvider implements BlockAPI {
@@ -34,17 +35,26 @@ final class BlockAPIProvider extends BasicProvider implements BlockAPI {
     public Optional<BlockUncle> uncles(long blockNumber) throws EtherScanException {
         final String urlParam = ACT_BLOCK_PARAM + BLOCKNO_PARAM + blockNumber;
         final byte[] response = getRequest(urlParam);
-        if (response.length == 0)
-            return Optional.empty();
-
-        final UncleBlockResponseTO responseTO = convert(response, UncleBlockResponseTO.class);
-        if (responseTO.getMessage().equals("NOTOK")) {
+        if (response.length == 0) {
             return Optional.empty();
         }
 
-        BasicUtils.validateTxResponse(responseTO);
-        return (responseTO.getResult() == null || responseTO.getResult().isEmpty())
-                ? Optional.empty()
-                : Optional.of(responseTO.getResult());
+        try {
+            final UncleBlockResponseTO responseTO = convert(response, UncleBlockResponseTO.class);
+            if (responseTO.getMessage().startsWith("NOTOK")) {
+                return Optional.empty();
+            }
+
+            BasicUtils.validateTxResponse(responseTO);
+            return (responseTO.getResult() == null || responseTO.getResult().isEmpty())
+                    ? Optional.empty()
+                    : Optional.of(responseTO.getResult());
+        } catch (EtherScanResponseException e) {
+            if (e.getResponse().getMessage().startsWith("NOTOK")) {
+                return Optional.empty();
+            } else {
+                throw e;
+            }
+        }
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index 7b75240..bbb7335 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -36,7 +36,7 @@ public Abi contractAbi(String address) throws EtherScanException {
 
         final String urlParam = ACT_ABI_PARAM + ADDRESS_PARAM + address;
         final StringResponseTO response = getRequest(urlParam, StringResponseTO.class);
-        if (response.getStatus() != 1 && "NOTOK".equals(response.getMessage())) {
+        if (response.getStatus() != 1 && response.getMessage().startsWith("NOTOK")) {
             throw new EtherScanResponseException(response);
         }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
index dffb1aa..6da3d8f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -37,11 +37,6 @@ public interface EtherScanAPI extends AutoCloseable {
     @NotNull
     GasTrackerAPI gasTracker();
 
-    @NotNull
-    static EtherScanAPI build() {
-        return builder().build();
-    }
-
     @NotNull
     static Builder builder() {
         return new EthScanAPIBuilder();
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index 27e00df..a33f7c1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -13,6 +13,7 @@
 import io.goodforgod.api.etherscan.model.proxy.utility.StringProxyTO;
 import io.goodforgod.api.etherscan.model.proxy.utility.TxInfoProxyTO;
 import io.goodforgod.api.etherscan.model.proxy.utility.TxProxyTO;
+import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.util.Optional;
 import java.util.regex.Pattern;
@@ -142,10 +143,17 @@ public Optional<String> txSendRaw(String hexEncodedTx) throws EtherScanException
 
         final String urlParams = ACT_SEND_RAW_TX_PARAM + HEX_PARAM + hexEncodedTx;
         final StringProxyTO response = postRequest(urlParams, "", StringProxyTO.class);
-        if (response.getError() != null)
-            throw new EtherScanResponseException("Error occurred with code " + response.getError().getCode()
+        if (response.getError() != null) {
+            final StringResponseTO responseError = StringResponseTO.builder()
+                    .withStatus("0")
+                    .withMessage(response.getError().getMessage())
+                    .withResult(response.getError().getCode())
+                    .build();
+
+            throw new EtherScanResponseException(responseError, "Error occurred with code " + response.getError().getCode()
                     + " with message " + response.getError().getMessage()
                     + ", error id " + response.getId() + ", jsonRPC " + response.getJsonrpc());
+        }
 
         return Optional.ofNullable(response.getResult());
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/ErtherScanLogQueryException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanLogQueryException.java
similarity index 50%
rename from src/main/java/io/goodforgod/api/etherscan/error/ErtherScanLogQueryException.java
rename to src/main/java/io/goodforgod/api/etherscan/error/EtherScanLogQueryException.java
index b39dcee..e72d682 100644
--- a/src/main/java/io/goodforgod/api/etherscan/error/ErtherScanLogQueryException.java
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanLogQueryException.java
@@ -4,9 +4,9 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-public class ErtherScanLogQueryException extends EtherScanException {
+public class EtherScanLogQueryException extends EtherScanException {
 
-    public ErtherScanLogQueryException(String message) {
+    public EtherScanLogQueryException(String message) {
         super(message);
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java
index 21da798..19785ce 100644
--- a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanResponseException.java
@@ -9,15 +9,23 @@
  */
 public class EtherScanResponseException extends EtherScanException {
 
+    private final transient BaseResponseTO response;
+
     public EtherScanResponseException(BaseResponseTO response) {
-        this(response.getMessage() + ", with status: " + response.getStatus());
+        this(response, response.getMessage() + ", with status: " + response.getStatus());
     }
 
     public EtherScanResponseException(StringResponseTO response) {
-        this(response.getResult() + ", with status: " + response.getStatus() + ", with message: " + response.getMessage());
+        this(response,
+                response.getResult() + ", with status: " + response.getStatus() + ", with message: " + response.getMessage());
     }
 
-    public EtherScanResponseException(String message) {
+    public EtherScanResponseException(BaseResponseTO response, String message) {
         super(message);
+        this.response = response;
+    }
+
+    public BaseResponseTO getResponse() {
+        return response;
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
index 716cfa4..549bd47 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
@@ -1,7 +1,7 @@
 package io.goodforgod.api.etherscan.model.query;
 
 import io.goodforgod.api.etherscan.LogsAPI;
-import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import org.jetbrains.annotations.NotNull;
 
@@ -40,27 +40,27 @@ final class LogQueryBuilderImpl implements LogQuery.Builder {
     @Override
     public @NotNull LogTopicSingle withTopic(@NotNull String topic0) {
         if (BasicUtils.isNotHex(topic0))
-            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic0 can not be empty or non hex.");
         return new LogTopicSingle(address, startBlock, endBlock, topic0);
     }
 
     @Override
     public @NotNull LogTopicTuple withTopic(@NotNull String topic0, @NotNull String topic1) {
         if (BasicUtils.isNotHex(topic0))
-            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic0 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic1))
-            throw new ErtherScanLogQueryException("topic1 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic1 can not be empty or non hex.");
         return new LogTopicTuple(address, startBlock, endBlock, topic0, topic1);
     }
 
     @Override
     public @NotNull LogTopicTriple withTopic(@NotNull String topic0, @NotNull String topic1, @NotNull String topic2) {
         if (BasicUtils.isNotHex(topic0))
-            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic0 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic1))
-            throw new ErtherScanLogQueryException("topic1 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic1 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic2))
-            throw new ErtherScanLogQueryException("topic2 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic2 can not be empty or non hex.");
         return new LogTopicTriple(address, startBlock, endBlock, topic0, topic1, topic2);
     }
 
@@ -68,19 +68,19 @@ final class LogQueryBuilderImpl implements LogQuery.Builder {
     public @NotNull LogTopicQuadro
             withTopic(@NotNull String topic0, @NotNull String topic1, @NotNull String topic2, @NotNull String topic3) {
         if (BasicUtils.isNotHex(topic0))
-            throw new ErtherScanLogQueryException("topic0 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic0 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic1))
-            throw new ErtherScanLogQueryException("topic1 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic1 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic2))
-            throw new ErtherScanLogQueryException("topic2 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic2 can not be empty or non hex.");
         if (BasicUtils.isNotHex(topic3))
-            throw new ErtherScanLogQueryException("topic3 can not be empty or non hex.");
+            throw new EtherScanLogQueryException("topic3 can not be empty or non hex.");
 
         return new LogTopicQuadro(address, startBlock, endBlock, topic0, topic1, topic2, topic3);
     }
 
     @Override
-    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
+    public @NotNull LogQuery build() throws EtherScanLogQueryException {
         return new LogQueryImpl("&address=" + this.address + "&fromBlock=" + this.startBlock + "&toBlock=" + this.endBlock);
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
index 1469f97..7fdd9db 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
@@ -3,7 +3,7 @@
 import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
 
 import io.goodforgod.api.etherscan.LogsAPI;
-import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -71,17 +71,17 @@ public LogTopicQuadro setOpTopic1_3(LogOp topic1_3_opr) {
     @Override
     public @NotNull LogQuery build() {
         if (topic0_1_opr == null)
-            throw new ErtherScanLogQueryException("topic0_1_opr can not be null.");
+            throw new EtherScanLogQueryException("topic0_1_opr can not be null.");
         if (topic0_2_opr == null)
-            throw new ErtherScanLogQueryException("topic0_2_opr can not be null.");
+            throw new EtherScanLogQueryException("topic0_2_opr can not be null.");
         if (topic0_3_opr == null)
-            throw new ErtherScanLogQueryException("topic0_3_opr can not be null.");
+            throw new EtherScanLogQueryException("topic0_3_opr can not be null.");
         if (topic1_2_opr == null)
-            throw new ErtherScanLogQueryException("topic1_2_opr can not be null.");
+            throw new EtherScanLogQueryException("topic1_2_opr can not be null.");
         if (topic2_3_opr == null)
-            throw new ErtherScanLogQueryException("topic2_3_opr can not be null.");
+            throw new EtherScanLogQueryException("topic2_3_opr can not be null.");
         if (topic1_3_opr == null)
-            throw new ErtherScanLogQueryException("topic1_3_opr can not be null.");
+            throw new EtherScanLogQueryException("topic1_3_opr can not be null.");
 
         return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
index 85bd18c..a736ffa 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
@@ -3,7 +3,7 @@
 import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
 
 import io.goodforgod.api.etherscan.LogsAPI;
-import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -29,7 +29,7 @@ public final class LogTopicSingle implements LogTopicBuilder {
     }
 
     @Override
-    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
+    public @NotNull LogQuery build() throws EtherScanLogQueryException {
         return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
                 + TOPIC_0_PARAM + topic0);
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
index d56edb5..ac9efb8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
@@ -3,7 +3,7 @@
 import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
 
 import io.goodforgod.api.etherscan.LogsAPI;
-import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -52,13 +52,13 @@ public LogTopicTriple setOpTopic1_2(LogOp topic1_2_opr) {
     }
 
     @Override
-    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
+    public @NotNull LogQuery build() throws EtherScanLogQueryException {
         if (topic0_1_opr == null)
-            throw new ErtherScanLogQueryException("topic0_1_opr can not be null.");
+            throw new EtherScanLogQueryException("topic0_1_opr can not be null.");
         if (topic0_2_opr == null)
-            throw new ErtherScanLogQueryException("topic0_2_opr can not be null.");
+            throw new EtherScanLogQueryException("topic0_2_opr can not be null.");
         if (topic1_2_opr == null)
-            throw new ErtherScanLogQueryException("topic1_2_opr can not be null.");
+            throw new EtherScanLogQueryException("topic1_2_opr can not be null.");
 
         return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
index 95a78a4..2ef2bba 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
@@ -3,7 +3,7 @@
 import static io.goodforgod.api.etherscan.model.query.LogQueryParams.*;
 
 import io.goodforgod.api.etherscan.LogsAPI;
-import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
+import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -40,9 +40,9 @@ public LogTopicTuple setOpTopic0_1(LogOp topic0_1_opr) {
     }
 
     @Override
-    public @NotNull LogQuery build() throws ErtherScanLogQueryException {
+    public @NotNull LogQuery build() throws EtherScanLogQueryException {
         if (topic0_1_opr == null)
-            throw new ErtherScanLogQueryException("topic0_1_opr can not be null.");
+            throw new EtherScanLogQueryException("topic0_1_opr can not be null.");
 
         return new LogQueryImpl(ADDRESS_PARAM + address
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/BaseResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/BaseResponseTO.java
index 3e100d1..46c6ca0 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/BaseResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/BaseResponseTO.java
@@ -8,8 +8,8 @@
  */
 public abstract class BaseResponseTO {
 
-    private String status;
-    private String message;
+    String status;
+    String message;
 
     public int getStatus() {
         return BasicUtils.isEmpty(status)
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
index 4fb9f04..19fa0a1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
@@ -11,4 +11,40 @@ public class StringResponseTO extends BaseResponseTO {
     public String getResult() {
         return result;
     }
+
+    public static StringResponseBuilder builder() {
+        return new StringResponseBuilder();
+    }
+
+    public static final class StringResponseBuilder {
+
+        private String status;
+        private String message;
+        private String result;
+
+        private StringResponseBuilder() {}
+
+        public StringResponseBuilder withStatus(String status) {
+            this.status = status;
+            return this;
+        }
+
+        public StringResponseBuilder withMessage(String message) {
+            this.message = message;
+            return this;
+        }
+
+        public StringResponseBuilder withResult(String result) {
+            this.result = result;
+            return this;
+        }
+
+        public StringResponseTO build() {
+            StringResponseTO stringResponseTO = new StringResponseTO();
+            stringResponseTO.status = this.status;
+            stringResponseTO.message = this.message;
+            stringResponseTO.result = this.result;
+            return stringResponseTO;
+        }
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
index eda3ce2..216ab62 100644
--- a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
+++ b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
@@ -5,6 +5,7 @@
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import io.goodforgod.api.etherscan.model.response.BaseResponseTO;
 import io.goodforgod.api.etherscan.model.response.BlockParam;
+import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import java.math.BigInteger;
 import java.util.*;
 import java.util.regex.Pattern;
@@ -98,12 +99,17 @@ public static void validateTxHash(String txhash) {
     }
 
     public static <T extends BaseResponseTO> void validateTxResponse(T response) {
-        if (response == null)
-            throw new EtherScanResponseException("EtherScan responded with null value");
+        if (response == null) {
+            final StringResponseTO emptyResponse = StringResponseTO.builder()
+                    .withStatus("0")
+                    .withMessage("EtherScan responded with null value")
+                    .build();
+            throw new EtherScanResponseException(emptyResponse, "EtherScan responded with null value");
+        }
 
         if (response.getStatus() != 1) {
             if (response.getMessage() == null) {
-                throw new EtherScanResponseException(
+                throw new EtherScanResponseException(response,
                         "Unexpected Etherscan exception, no information from server about error, code " + response.getStatus());
             } else if (!response.getMessage().startsWith("No tra") && !response.getMessage().startsWith("No rec")) {
                 throw new EtherScanResponseException(response);
diff --git a/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTests.java
index 339f07e..955443c 100644
--- a/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/logs/LogQueryBuilderTests.java
@@ -1,8 +1,8 @@
 package io.goodforgod.api.etherscan.logs;
 
 import io.goodforgod.api.etherscan.ApiRunner;
-import io.goodforgod.api.etherscan.error.ErtherScanLogQueryException;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
 import io.goodforgod.api.etherscan.model.query.*;
 import org.junit.jupiter.api.Test;
 
@@ -32,7 +32,7 @@ void singleInCorrectAddress() {
 
     @Test
     void singleInCorrectTopic() {
-        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+        assertThrows(EtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .withTopic("6516=")
                 .build());
     }
@@ -51,7 +51,7 @@ void tupleCorrect() {
 
     @Test
     void tupleInCorrectOp() {
-        assertThrows(ErtherScanLogQueryException.class,
+        assertThrows(EtherScanLogQueryException.class,
                 () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224)
                         .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000")
@@ -76,7 +76,7 @@ void tripleCorrect() {
 
     @Test
     void tripleInCorrectOp() {
-        assertThrows(ErtherScanLogQueryException.class,
+        assertThrows(EtherScanLogQueryException.class,
                 () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
                         .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -89,7 +89,7 @@ void tripleInCorrectOp() {
 
     @Test
     void tripleInCorrectTopic1() {
-        assertThrows(ErtherScanLogQueryException.class,
+        assertThrows(EtherScanLogQueryException.class,
                 () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
                         .withTopic(null,
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -102,7 +102,7 @@ void tripleInCorrectTopic1() {
 
     @Test
     void tripleInCorrectTopic2() {
-        assertThrows(ErtherScanLogQueryException.class,
+        assertThrows(EtherScanLogQueryException.class,
                 () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
                         .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                                 null,
@@ -115,7 +115,7 @@ void tripleInCorrectTopic2() {
 
     @Test
     void tripleInCorrectTopic3() {
-        assertThrows(ErtherScanLogQueryException.class,
+        assertThrows(EtherScanLogQueryException.class,
                 () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c").withBlockFrom(379224).withBlockTo(400000)
                         .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                                 "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -147,7 +147,7 @@ void quadroCorrect() {
 
     @Test
     void quadroIncorrectTopic2() {
-        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+        assertThrows(EtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         null,
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -163,7 +163,7 @@ void quadroIncorrectTopic2() {
 
     @Test
     void tupleIncorrectTopic2() {
-        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+        assertThrows(EtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         null)
                 .setOpTopic0_1(LogOp.AND)
@@ -172,7 +172,7 @@ void tupleIncorrectTopic2() {
 
     @Test
     void tupleIncorrectTopic1() {
-        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+        assertThrows(EtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .withTopic(null,
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
                 .setOpTopic0_1(LogOp.AND)
@@ -187,7 +187,7 @@ void quadroIncorrectOp1() {
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
+        assertThrows(EtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(null)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -205,7 +205,7 @@ void quadroIncorrectOp2() {
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro.setOpTopic0_1(LogOp.AND)
+        assertThrows(EtherScanLogQueryException.class, () -> topicQuadro.setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(null)
                 .setOpTopic0_3(LogOp.AND)
                 .setOpTopic1_2(LogOp.OR)
@@ -222,7 +222,7 @@ void quadroIncorrectOp3() {
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000");
 
-        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
+        assertThrows(EtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(null)
@@ -234,7 +234,7 @@ void quadroIncorrectOp3() {
 
     @Test
     void quadroInCorrectAgainTopic() {
-        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+        assertThrows(EtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
@@ -256,7 +256,7 @@ void quadroInCorrectOp4() {
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
+        assertThrows(EtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -274,7 +274,7 @@ void quadroInCorrectOp5() {
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
+        assertThrows(EtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -292,7 +292,7 @@ void quadroInCorrectOp6() {
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545");
 
-        assertThrows(ErtherScanLogQueryException.class, () -> topicQuadro
+        assertThrows(EtherScanLogQueryException.class, () -> topicQuadro
                 .setOpTopic0_1(LogOp.AND)
                 .setOpTopic0_2(LogOp.OR)
                 .setOpTopic0_3(LogOp.AND)
@@ -304,7 +304,7 @@ void quadroInCorrectOp6() {
 
     @Test
     void quadroInCorrectTopic() {
-        assertThrows(ErtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+        assertThrows(EtherScanLogQueryException.class, () -> LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
                 .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545",
                         "0x72657075746174696f6e00000000000000000000000000000000000000000000",
                         "",

From 25751ab85f0dd4d87fb78d3495ac20f8e0dd9da4 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 22:11:09 +0300
Subject: [PATCH 35/67] [2.0.0-SNAPSHOT] Default converter parsing optimized

---
 .../goodforgod/api/etherscan/EthScanAPIBuilder.java   | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index 69474d9..57aeeae 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -2,11 +2,15 @@
 
 import com.google.gson.Gson;
 import io.goodforgod.api.etherscan.error.EtherScanKeyException;
+import io.goodforgod.api.etherscan.error.EtherScanParseException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import io.goodforgod.gson.configuration.GsonConfiguration;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.util.function.Supplier;
 import org.jetbrains.annotations.NotNull;
@@ -30,8 +34,11 @@ final class EthScanAPIBuilder implements EtherScanAPI.Builder {
 
         @Override
         public <T> @NotNull T fromJson(byte[] jsonAsByteArray, @NotNull Class<T> type) {
-            final String jsonAsString = new String(jsonAsByteArray, StandardCharsets.UTF_8);
-            return gson.fromJson(jsonAsString, type);
+            try (InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(jsonAsByteArray))) {
+                return gson.fromJson(isr, type);
+            } catch (IOException e) {
+                throw new EtherScanParseException(e.getMessage(), e, new String(jsonAsByteArray, StandardCharsets.UTF_8));
+            }
         }
     };
 

From 47e04a832fb504c4e7469d77cf18beb865820b55 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 22:41:24 +0300
Subject: [PATCH 36/67] [2.0.0-SNAPSHOT] EthSupply for StatisticAPI#supplyTotal
 added Javadoc fixed

---
 .../goodforgod/api/etherscan/AccountAPI.java  |   2 +-
 .../api/etherscan/AccountAPIProvider.java     |   6 +-
 .../io/goodforgod/api/etherscan/BlockAPI.java |   2 +-
 .../goodforgod/api/etherscan/ContractAPI.java |   2 +-
 .../io/goodforgod/api/etherscan/LogsAPI.java  |   2 +-
 .../io/goodforgod/api/etherscan/ProxyAPI.java |   3 +-
 .../api/etherscan/ProxyAPIProvider.java       |   8 +-
 .../api/etherscan/StatisticAPI.java           |  29 +++--
 .../api/etherscan/StatisticAPIProvider.java   |  24 +++-
 .../api/etherscan/TransactionAPI.java         |   2 +-
 .../api/etherscan/model/EthSupply.java        | 110 ++++++++++++++++++
 .../api/etherscan/model/GasOracle.java        |   6 +-
 .../api/etherscan/model/Supply.java           |  18 ---
 .../goodforgod/api/etherscan/model/Wei.java   |  40 ++++---
 .../model/response/EthSupplyResponseTO.java   |  16 +++
 .../gastracker/GasTrackerApiTests.java        |   2 +-
 .../etherscan/model/ModelBuilderTests.java    |   8 +-
 .../statistic/StatisticPriceApiTests.java     |   2 +-
 .../statistic/StatisticSupplyApiTests.java    |   6 +-
 .../StatisticSupplyTotalApiTests.java         |  28 +++++
 .../StatisticTokenSupplyApiTests.java         |   7 +-
 21 files changed, 250 insertions(+), 73 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/model/Supply.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/EthSupplyResponseTO.java
 create mode 100644 src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyTotalApiTests.java

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
index 294fb2a..45be8b8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
@@ -6,7 +6,7 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions <a href="https://etherscan.io/apis#accounts">...</a>
+ * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/accounts">...</a>
  *
  * @author GoodforGod
  * @since 28.10.2018
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 11bb192..e5b6bd9 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -64,7 +64,7 @@ public Balance balance(String address) throws EtherScanException {
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
-        return new Balance(address, new Wei(new BigInteger(response.getResult())));
+        return new Balance(address, Wei.ofWei(new BigInteger(response.getResult())));
     }
 
     @NotNull
@@ -78,7 +78,7 @@ public TokenBalance balance(String address, String contract) throws EtherScanExc
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
-        return new TokenBalance(address, new Wei(new BigInteger(response.getResult())), contract);
+        return new TokenBalance(address, Wei.ofWei(new BigInteger(response.getResult())), contract);
     }
 
     @NotNull
@@ -101,7 +101,7 @@ public List<Balance> balances(List<String> addresses) throws EtherScanException
 
             if (!BasicUtils.isEmpty(response.getResult()))
                 balances.addAll(response.getResult().stream()
-                        .map(r -> new Balance(r.getAccount(), new Wei(new BigInteger(r.getBalance()))))
+                        .map(r -> new Balance(r.getAccount(), Wei.ofWei(new BigInteger(r.getBalance()))))
                         .collect(Collectors.toList()));
         }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/BlockAPI.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPI.java
index 55a8c3b..fdacaf5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BlockAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPI.java
@@ -6,7 +6,7 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions <a href="https://etherscan.io/apis#blocks">...</a>
+ * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/blocks">...</a>
  *
  * @author GoodforGod
  * @since 30.10.2018
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
index 9271347..7564c98 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
@@ -5,7 +5,7 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions <a href="https://etherscan.io/apis#contracts">...</a>
+ * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/contracts">...</a>
  *
  * @author GoodforGod
  * @since 28.10.2018
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
index 5b834df..01d79f7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
@@ -7,7 +7,7 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions <a href="https://etherscan.io/apis#logs">...</a>
+ * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/logs">...</a>
  *
  * @author GoodforGod
  * @since 30.10.2018
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
index b379290..77d6769 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
@@ -10,7 +10,8 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions <a href="https://etherscan.io/apis#proxy">...</a>
+ * EtherScan - API Descriptions
+ * <a href="https://docs.etherscan.io/api-endpoints/geth-parity-proxy">...</a>
  *
  * @author GoodforGod
  * @since 30.10.2018
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index a33f7c1..18edd90 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -208,8 +208,8 @@ public Optional<String> storageAt(String address, long position) throws EtherSca
     public Wei gasPrice() throws EtherScanException {
         final StringProxyTO response = getRequest(ACT_GASPRICE_PARAM, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
-                ? new Wei(0)
-                : new Wei(BasicUtils.parseHex(response.getResult()));
+                ? Wei.ofWei(0)
+                : Wei.ofWei(BasicUtils.parseHex(response.getResult()));
     }
 
     @NotNull
@@ -227,7 +227,7 @@ public Wei gasEstimated(String hexData) throws EtherScanException {
         final String urlParams = ACT_ESTIMATEGAS_PARAM + DATA_PARAM + hexData + GAS_PARAM + "2000000000000000";
         final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
-                ? new Wei(0)
-                : new Wei(BasicUtils.parseHex(response.getResult()));
+                ? Wei.ofWei(0)
+                : Wei.ofWei(BasicUtils.parseHex(response.getResult()));
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
index 314f73e..10e41e3 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
@@ -1,13 +1,13 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
+import io.goodforgod.api.etherscan.model.EthSupply;
 import io.goodforgod.api.etherscan.model.Price;
-import io.goodforgod.api.etherscan.model.Supply;
-import java.math.BigInteger;
+import io.goodforgod.api.etherscan.model.Wei;
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions <a href="https://etherscan.io/apis#stats">...</a>
+ * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/stats-1">...</a>
  *
  * @author GoodforGod
  * @since 30.10.2018
@@ -16,22 +16,35 @@ public interface StatisticAPI {
 
     /**
      * ERC20 token total Supply
-     * 
+     * <a href=
+     * "https://docs.etherscan.io/api-endpoints/tokens#get-erc20-token-totalsupply-by-contractaddress">EtherScan<a>
+     *
      * @param contract contract address
      * @return token supply for specified contract
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    BigInteger supply(String contract) throws EtherScanException;
+    Wei supply(String contract) throws EtherScanException;
 
     /**
-     * Eth total supply
+     * Returns the current amount of Ether in circulation excluding ETH2 Staking rewards and EIP1559
+     * burnt fees.
      * 
      * @return total ETH supply for moment
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Supply supply() throws EtherScanException;
+    Wei supply() throws EtherScanException;
+
+    /**
+     * Returns the current amount of Ether in circulation, ETH2 Staking rewards, EIP1559 burnt fees, and
+     * total withdrawn ETH from the beacon chain.
+     *
+     * @return total ETH supply for moment
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    EthSupply supplyTotal() throws EtherScanException;
 
     /**
      * Eth last USD and BTC price
@@ -40,5 +53,5 @@ public interface StatisticAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Price lastPrice() throws EtherScanException;
+    Price priceLast() throws EtherScanException;
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
index 1d1bcee..9555169 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
@@ -4,8 +4,10 @@
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.EthSupply;
 import io.goodforgod.api.etherscan.model.Price;
-import io.goodforgod.api.etherscan.model.Supply;
+import io.goodforgod.api.etherscan.model.Wei;
+import io.goodforgod.api.etherscan.model.response.EthSupplyResponseTO;
 import io.goodforgod.api.etherscan.model.response.PriceResponseTO;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import io.goodforgod.api.etherscan.util.BasicUtils;
@@ -22,6 +24,7 @@
 final class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
 
     private static final String ACT_SUPPLY_PARAM = ACT_PREFIX + "ethsupply";
+    private static final String ACT_SUPPLY2_PARAM = ACT_PREFIX + "ethsupply2";
     private static final String ACT_TOKEN_SUPPLY_PARAM = ACT_PREFIX + "tokensupply";
     private static final String ACT_LASTPRICE_PARAM = ACT_PREFIX + "ethprice";
 
@@ -36,17 +39,26 @@ final class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
 
     @NotNull
     @Override
-    public Supply supply() throws EtherScanException {
+    public Wei supply() throws EtherScanException {
         final StringResponseTO response = getRequest(ACT_SUPPLY_PARAM, StringResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
-        return new Supply(new BigInteger(response.getResult()));
+        return Wei.ofWei(new BigInteger(response.getResult()));
+    }
+
+    @Override
+    public @NotNull EthSupply supplyTotal() throws EtherScanException {
+        final EthSupplyResponseTO response = getRequest(ACT_SUPPLY2_PARAM, EthSupplyResponseTO.class);
+        if (response.getStatus() != 1)
+            throw new EtherScanResponseException(response);
+
+        return response.getResult();
     }
 
     @NotNull
     @Override
-    public BigInteger supply(String contract) throws EtherScanException {
+    public Wei supply(String contract) throws EtherScanException {
         BasicUtils.validateAddress(contract);
 
         final String urlParams = ACT_TOKEN_SUPPLY_PARAM + CONTRACT_ADDRESS_PARAM + contract;
@@ -54,12 +66,12 @@ public BigInteger supply(String contract) throws EtherScanException {
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
-        return new BigInteger(response.getResult());
+        return Wei.ofWei(new BigInteger(response.getResult()));
     }
 
     @NotNull
     @Override
-    public Price lastPrice() throws EtherScanException {
+    public Price priceLast() throws EtherScanException {
         final PriceResponseTO response = getRequest(ACT_LASTPRICE_PARAM, PriceResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
diff --git a/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
index 6bfc545..a89a4a6 100644
--- a/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
@@ -6,7 +6,7 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * EtherScan - API Descriptions <a href="https://etherscan.io/apis#transactions">...</a>
+ * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/stats">...</a>
  *
  * @author GoodforGod
  * @since 30.10.2018
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
new file mode 100644
index 0000000..f967360
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
@@ -0,0 +1,110 @@
+package io.goodforgod.api.etherscan.model;
+
+import java.math.BigInteger;
+import java.util.Objects;
+
+/**
+ * Please Add Description Here.
+ *
+ * @author Anton Kurako (GoodforGod)
+ * @since 14.05.2023
+ */
+public class EthSupply {
+
+    private String EthSupply;
+    private String Eth2Staking;
+    private String BurntFees;
+    private String WithdrawnTotal;
+
+    public Wei getEthSupply() {
+        return Wei.ofWei(new BigInteger(EthSupply));
+    }
+
+    public Wei getEth2Staking() {
+        return Wei.ofWei(new BigInteger(Eth2Staking));
+    }
+
+    public Wei getBurntFees() {
+        return Wei.ofWei(new BigInteger(BurntFees));
+    }
+
+    public Wei getTotal() {
+        final BigInteger total = getEthSupply().asWei()
+                .add(getEth2Staking().asWei())
+                .min(getBurntFees().asWei());
+        return Wei.ofWei(total);
+    }
+
+    public Wei getWithdrawnTotal() {
+        return Wei.ofWei(new BigInteger(WithdrawnTotal));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (!(o instanceof EthSupply))
+            return false;
+        EthSupply ethSupply = (EthSupply) o;
+        return Objects.equals(EthSupply, ethSupply.EthSupply) && Objects.equals(Eth2Staking, ethSupply.Eth2Staking)
+                && Objects.equals(BurntFees, ethSupply.BurntFees) && Objects.equals(WithdrawnTotal, ethSupply.WithdrawnTotal);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(EthSupply, Eth2Staking, BurntFees, WithdrawnTotal);
+    }
+
+    @Override
+    public String toString() {
+        return "EthSupply{" +
+                "EthSupply='" + EthSupply + '\'' +
+                ", Eth2Staking='" + Eth2Staking + '\'' +
+                ", BurntFees='" + BurntFees + '\'' +
+                ", WithdrawnTotal='" + WithdrawnTotal + '\'' +
+                '}';
+    }
+
+    public static EthSupplyBuilder builder() {
+        return new EthSupplyBuilder();
+    }
+
+    public static final class EthSupplyBuilder {
+
+        private Wei ethSupply;
+        private Wei eth2Staking;
+        private Wei burntFees;
+        private Wei withdrawnTotal;
+
+        private EthSupplyBuilder() {}
+
+        public EthSupplyBuilder withEthSupply(Wei ethSupply) {
+            this.ethSupply = ethSupply;
+            return this;
+        }
+
+        public EthSupplyBuilder withEth2Staking(Wei eth2Staking) {
+            this.eth2Staking = eth2Staking;
+            return this;
+        }
+
+        public EthSupplyBuilder withBurntFees(Wei burntFees) {
+            this.burntFees = burntFees;
+            return this;
+        }
+
+        public EthSupplyBuilder withWithdrawnTotal(Wei withdrawnTotal) {
+            this.withdrawnTotal = withdrawnTotal;
+            return this;
+        }
+
+        public EthSupply build() {
+            EthSupply ethSupply = new EthSupply();
+            ethSupply.BurntFees = this.burntFees.toString();
+            ethSupply.Eth2Staking = this.eth2Staking.toString();
+            ethSupply.EthSupply = this.ethSupply.toString();
+            ethSupply.WithdrawnTotal = this.withdrawnTotal.toString();
+            return ethSupply;
+        }
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
index 67dd82a..d273357 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
@@ -27,15 +27,15 @@ public Long getLastBlock() {
     }
 
     public Wei getSafeGasPriceInWei() {
-        return new Wei(BigInteger.valueOf(SafeGasPrice).multiply(BigInteger.TEN.pow(9)));
+        return Wei.ofWei(BigInteger.valueOf(SafeGasPrice).multiply(BigInteger.TEN.pow(9)));
     }
 
     public Wei getProposeGasPriceInWei() {
-        return new Wei(BigInteger.valueOf(ProposeGasPrice).multiply(BigInteger.TEN.pow(9)));
+        return Wei.ofWei(BigInteger.valueOf(ProposeGasPrice).multiply(BigInteger.TEN.pow(9)));
     }
 
     public Wei getFastGasPriceInWei() {
-        return new Wei(BigInteger.valueOf(FastGasPrice).multiply(BigInteger.TEN.pow(9)));
+        return Wei.ofWei(BigInteger.valueOf(FastGasPrice).multiply(BigInteger.TEN.pow(9)));
     }
 
     public Double getSuggestBaseFee() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Supply.java b/src/main/java/io/goodforgod/api/etherscan/model/Supply.java
deleted file mode 100644
index 43e3a3f..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/model/Supply.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package io.goodforgod.api.etherscan.model;
-
-import java.math.BigInteger;
-
-/**
- * @author GoodforGod
- * @since 30.10.2018
- */
-public class Supply extends Wei {
-
-    public Supply(long value) {
-        super(value);
-    }
-
-    public Supply(BigInteger value) {
-        super(value);
-    }
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index e23ea51..004b5e1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -11,16 +11,32 @@ public class Wei {
 
     private final BigInteger result;
 
-    public Wei(int value) {
-        this.result = BigInteger.valueOf(value);
+    private Wei(BigInteger value) {
+        this.result = value;
     }
 
-    public Wei(long value) {
-        this.result = BigInteger.valueOf(value);
+    public static Wei ofWei(int value) {
+        return new Wei(BigInteger.valueOf(value));
     }
 
-    public Wei(BigInteger value) {
-        this.result = value;
+    public static Wei ofWei(long value) {
+        return new Wei(BigInteger.valueOf(value));
+    }
+
+    public static Wei ofWei(BigInteger value) {
+        return new Wei(value);
+    }
+
+    public static Wei ofEther(int value) {
+        return new Wei(BigInteger.valueOf(value).multiply(BigInteger.valueOf(1_000_000_000_000_000L)));
+    }
+
+    public static Wei ofEther(long value) {
+        return new Wei(BigInteger.valueOf(value).multiply(BigInteger.valueOf(1_000_000_000_000_000L)));
+    }
+
+    public static Wei ofEther(BigInteger value) {
+        return new Wei(value.multiply(BigInteger.valueOf(1_000_000_000_000_000L)));
     }
 
     // <editor-fold desc="Getters">
@@ -29,19 +45,19 @@ public BigInteger asWei() {
     }
 
     public BigInteger asKwei() {
-        return result.divide(BigInteger.valueOf(1000));
+        return result.divide(BigInteger.valueOf(1_000));
     }
 
     public BigInteger asMwei() {
-        return result.divide(BigInteger.valueOf(1000000));
+        return result.divide(BigInteger.valueOf(1_000_000));
     }
 
     public BigInteger asGwei() {
-        return result.divide(BigInteger.valueOf(1000000000));
+        return result.divide(BigInteger.valueOf(1_000_000_000));
     }
 
     public BigInteger asEther() {
-        return result.divide(BigInteger.valueOf(1000000000000000L));
+        return result.divide(BigInteger.valueOf(1_000_000_000_000_000L));
     }
     // </editor-fold>
 
@@ -62,8 +78,6 @@ public int hashCode() {
 
     @Override
     public String toString() {
-        return "Wei{" +
-                "result=" + result +
-                '}';
+        return result.toString();
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/EthSupplyResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/EthSupplyResponseTO.java
new file mode 100644
index 0000000..edbc2e3
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/EthSupplyResponseTO.java
@@ -0,0 +1,16 @@
+package io.goodforgod.api.etherscan.model.response;
+
+import io.goodforgod.api.etherscan.model.EthSupply;
+
+/**
+ * @author GoodforGod
+ * @since 14.05.2023
+ */
+public class EthSupplyResponseTO extends BaseResponseTO {
+
+    private EthSupply result;
+
+    public EthSupply getResult() {
+        return result;
+    }
+}
diff --git a/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
index 1d92eb4..53b1c2c 100644
--- a/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
@@ -14,7 +14,7 @@ class GasTrackerApiTests extends ApiRunner {
 
     @Test
     void estimate() {
-        GasEstimate estimate = getApi().gasTracker().estimate(new Wei(123));
+        GasEstimate estimate = getApi().gasTracker().estimate(Wei.ofWei(123));
         assertNotNull(estimate);
         assertNotNull(estimate.getDuration());
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index 1bec491..9a7e426 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -65,16 +65,16 @@ void blockUncleBuilder() {
     @Test
     void gasOracleBuilder() {
         GasOracle value = GasOracle.builder()
-                .withFastGasPrice(new Wei(1000000000))
-                .withProposeGasPrice(new Wei(1000000000))
-                .withSafeGasPrice(new Wei(1000000000))
+                .withFastGasPrice(Wei.ofWei(1000000000))
+                .withProposeGasPrice(Wei.ofWei(1000000000))
+                .withSafeGasPrice(Wei.ofWei(1000000000))
                 .withGasUsedRatio(Collections.singletonList(new BigDecimal(1)))
                 .withLastBlock(1L)
                 .withSuggestBaseFee(1.0)
                 .build();
 
         assertNotNull(value);
-        assertEquals(new Wei(1000000000), value.getFastGasPriceInWei());
+        assertEquals(Wei.ofWei(1000000000), value.getFastGasPriceInWei());
     }
 
     @Test
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
index 3525e21..0dd89c2 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
@@ -12,7 +12,7 @@ class StatisticPriceApiTests extends ApiRunner {
 
     @Test
     void correct() {
-        Price price = getApi().stats().lastPrice();
+        Price price = getApi().stats().priceLast();
         assertNotNull(price);
         assertNotNull(price.btcTimestamp());
         assertNotNull(price.usdTimestamp());
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
index 56469a9..6564c93 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyApiTests.java
@@ -1,7 +1,7 @@
 package io.goodforgod.api.etherscan.statistic;
 
 import io.goodforgod.api.etherscan.ApiRunner;
-import io.goodforgod.api.etherscan.model.Supply;
+import io.goodforgod.api.etherscan.model.Wei;
 import java.math.BigInteger;
 import org.junit.jupiter.api.Test;
 
@@ -13,7 +13,7 @@ class StatisticSupplyApiTests extends ApiRunner {
 
     @Test
     void correct() {
-        Supply supply = getApi().stats().supply();
+        Wei supply = getApi().stats().supply();
         assertNotNull(supply);
         assertNotNull(supply.asWei());
         assertNotNull(supply.asGwei());
@@ -22,7 +22,7 @@ void correct() {
         assertNotNull(supply.asEther());
         assertNotNull(supply.toString());
 
-        Supply empty = new Supply(BigInteger.ONE);
+        Wei empty = Wei.ofWei(BigInteger.ONE);
         assertNotEquals(supply, empty);
         assertNotEquals(supply.hashCode(), empty.hashCode());
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyTotalApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyTotalApiTests.java
new file mode 100644
index 0000000..b6098d8
--- /dev/null
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticSupplyTotalApiTests.java
@@ -0,0 +1,28 @@
+package io.goodforgod.api.etherscan.statistic;
+
+import io.goodforgod.api.etherscan.ApiRunner;
+import io.goodforgod.api.etherscan.model.EthSupply;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author GoodforGod
+ * @since 14.05.2023
+ */
+class StatisticSupplyTotalApiTests extends ApiRunner {
+
+    @Test
+    void correct() {
+        EthSupply supply = getApi().stats().supplyTotal();
+        assertNotNull(supply);
+        assertNotNull(supply.getBurntFees());
+        assertNotEquals(0, supply.getBurntFees().asWei().intValue());
+        assertNotNull(supply.getEthSupply());
+        assertNotEquals(0, supply.getEthSupply().asWei().intValue());
+        assertNotNull(supply.getEth2Staking());
+        assertNotEquals(0, supply.getEth2Staking().asWei().intValue());
+        assertNotNull(supply.getWithdrawnTotal());
+        assertNotEquals(0, supply.getWithdrawnTotal().asWei().intValue());
+        assertNotNull(supply.getTotal());
+        assertNotEquals(0, supply.getTotal().asWei().intValue());
+    }
+}
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
index 07f8eca..b21b3b3 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
@@ -2,6 +2,7 @@
 
 import io.goodforgod.api.etherscan.ApiRunner;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
+import io.goodforgod.api.etherscan.model.Wei;
 import java.math.BigInteger;
 import org.junit.jupiter.api.Test;
 
@@ -13,7 +14,7 @@ class StatisticTokenSupplyApiTests extends ApiRunner {
 
     @Test
     void correct() {
-        BigInteger supply = getApi().stats().supply("0x57d90b64a1a57749b0f932f1a3395792e12e7055");
+        Wei supply = getApi().stats().supply("0x57d90b64a1a57749b0f932f1a3395792e12e7055");
         assertNotNull(supply);
         assertNotEquals(BigInteger.ZERO, supply);
     }
@@ -26,8 +27,8 @@ void invalidParamWithError() {
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        BigInteger supply = getApi().stats().supply("0x51d90b64a1a57749b0f932f1a3395792e12e7055");
+        Wei supply = getApi().stats().supply("0x51d90b64a1a57749b0f932f1a3395792e12e7055");
         assertNotNull(supply);
-        assertEquals(0, supply.intValue());
+        assertEquals(0, supply.asEther().intValue());
     }
 }

From 63f8909788f6bb48f91e5451bff71a9eda9e5ab3 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 14 May 2023 23:12:27 +0300
Subject: [PATCH 37/67] [2.0.0-SNAPSHOT] 1010L->1015L reset time

---
 .../api/etherscan/manager/RequestQueueManager.java     | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index 2fdfe82..4d6b586 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -16,16 +16,16 @@ public interface RequestQueueManager extends AutoCloseable {
     /**
      * Is used by default when no API KEY is provided
      */
-    RequestQueueManager ANONYMOUS = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5010L));
+    RequestQueueManager ANONYMOUS = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5015L));
 
     /**
      * Is available for all registered free API KEYs
      * <a href="https://docs.etherscan.io/getting-started/viewing-api-usage-statistics">Free API KEY</a>
      */
-    RequestQueueManager FREE_PLAN = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1010L));
-    RequestQueueManager STANDARD_PLAN = new SemaphoreRequestQueueManager(10, Duration.ofMillis(1010L));
-    RequestQueueManager ADVANCED_PLAN = new SemaphoreRequestQueueManager(20, Duration.ofMillis(1010L));
-    RequestQueueManager PROFESSIONAL_PLAN = new SemaphoreRequestQueueManager(30, Duration.ofMillis(1010L));
+    RequestQueueManager FREE_PLAN = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1015L));
+    RequestQueueManager STANDARD_PLAN = new SemaphoreRequestQueueManager(10, Duration.ofMillis(1015L));
+    RequestQueueManager ADVANCED_PLAN = new SemaphoreRequestQueueManager(20, Duration.ofMillis(1015L));
+    RequestQueueManager PROFESSIONAL_PLAN = new SemaphoreRequestQueueManager(30, Duration.ofMillis(1015L));
 
     RequestQueueManager UNLIMITED = new FakeRequestQueueManager();
 

From 6d19b737db506844f4aa821f71a37f0bfdf9ca8e Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 00:05:46 +0300
Subject: [PATCH 38/67] [2.0.0-SNAPSHOT] Gas related fields replaced to Wei

---
 .../api/etherscan/model/BaseTx.java           |  8 +-
 .../io/goodforgod/api/etherscan/model/Tx.java | 50 +++++++-----
 .../api/etherscan/model/TxErc1155.java        | 76 ++++++++++---------
 .../api/etherscan/model/TxErc20.java          | 40 ++++++----
 .../api/etherscan/model/TxErc721.java         | 40 ++++++----
 .../api/etherscan/model/TxInternal.java       | 16 ++--
 .../goodforgod/api/etherscan/model/Wei.java   | 22 ++++--
 .../api/etherscan/model/proxy/BlockProxy.java | 24 +++---
 .../etherscan/model/proxy/ReceiptProxy.java   | 24 +++---
 .../api/etherscan/model/proxy/TxProxy.java    | 24 +++---
 10 files changed, 180 insertions(+), 144 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
index c66e60f..64a9627 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
@@ -56,12 +56,12 @@ public String getInput() {
         return input;
     }
 
-    public BigInteger getGas() {
-        return gas;
+    public Wei getGas() {
+        return Wei.ofWei(gas);
     }
 
-    public BigInteger getGasUsed() {
-        return gasUsed;
+    public Wei getGasUsed() {
+        return Wei.ofWei(gasUsed);
     }
     // </editor-fold>
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 3d8cd1f..819252e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -41,20 +41,20 @@ public int getTransactionIndex() {
         return transactionIndex;
     }
 
-    public BigInteger getGasPrice() {
-        return gasPrice;
+    public Wei getGasPrice() {
+        return Wei.ofWei(gasPrice);
     }
 
     public boolean haveError() {
         return !BasicUtils.isEmpty(isError) && !isError.equals("0");
     }
 
-    public String getTxreceipt_status() {
+    public String getTxReceiptStatus() {
         return txreceipt_status;
     }
 
-    public BigInteger getCumulativeGasUsed() {
-        return cumulativeGasUsed;
+    public Wei getGasUsedCumulative() {
+        return Wei.ofWei(cumulativeGasUsed);
     }
 
     public long getConfirmations() {
@@ -112,16 +112,16 @@ public static final class TxBuilder {
         private BigInteger value;
         private String contractAddress;
         private String input;
-        private BigInteger gas;
-        private BigInteger gasUsed;
+        private Wei gas;
+        private Wei gasUsed;
         private long nonce;
         private String blockHash;
         private int transactionIndex;
-        private BigInteger gasPrice;
-        private BigInteger cumulativeGasUsed;
+        private Wei gasPrice;
+        private Wei cumulativeGasUsed;
         private long confirmations;
         private String isError;
-        private String txreceiptStatus;
+        private String txReceiptStatus;
 
         private TxBuilder() {}
 
@@ -165,12 +165,12 @@ public TxBuilder withInput(String input) {
             return this;
         }
 
-        public TxBuilder withGas(BigInteger gas) {
+        public TxBuilder withGas(Wei gas) {
             this.gas = gas;
             return this;
         }
 
-        public TxBuilder withGasUsed(BigInteger gasUsed) {
+        public TxBuilder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
@@ -190,12 +190,12 @@ public TxBuilder withTransactionIndex(int transactionIndex) {
             return this;
         }
 
-        public TxBuilder withGasPrice(BigInteger gasPrice) {
+        public TxBuilder withGasPrice(Wei gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public TxBuilder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
+        public TxBuilder withCumulativeGasUsed(Wei cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
@@ -210,20 +210,30 @@ public TxBuilder withIsError(String isError) {
             return this;
         }
 
-        public TxBuilder withTxreceiptStatus(String txreceiptStatus) {
-            this.txreceiptStatus = txreceiptStatus;
+        public TxBuilder withTxReceiptStatus(String txReceiptStatus) {
+            this.txReceiptStatus = txReceiptStatus;
             return this;
         }
 
         public Tx build() {
             Tx tx = new Tx();
-            tx.gas = this.gas;
             tx.isError = this.isError;
             tx.blockHash = this.blockHash;
             tx.hash = this.hash;
-            tx.gasUsed = this.gasUsed;
+            if (this.gas != null) {
+                tx.gas = this.gas.asWei();
+            }
+            if (this.gasUsed != null) {
+                tx.gasUsed = this.gasUsed.asWei();
+            }
+            if (this.gasPrice != null) {
+                tx.gasPrice = this.gasPrice.asWei();
+            }
+            if (this.cumulativeGasUsed != null) {
+                tx.cumulativeGasUsed = this.cumulativeGasUsed.asWei();
+            }
             tx.from = this.from;
-            tx.txreceipt_status = this.txreceiptStatus;
+            tx.txreceipt_status = this.txReceiptStatus;
             tx.contractAddress = this.contractAddress;
             tx.value = this.value;
             tx.transactionIndex = this.transactionIndex;
@@ -236,8 +246,6 @@ public Tx build() {
             tx.blockNumber = this.blockNumber;
             tx.to = this.to;
             tx.input = this.input;
-            tx.cumulativeGasUsed = this.cumulativeGasUsed;
-            tx.gasPrice = this.gasPrice;
             return tx;
         }
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
index e6c20f0..7be8aff 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -53,12 +53,12 @@ public int getTransactionIndex() {
         return transactionIndex;
     }
 
-    public BigInteger getGasPrice() {
-        return gasPrice;
+    public Wei getGasPrice() {
+        return Wei.ofWei(gasPrice);
     }
 
-    public BigInteger getCumulativeGasUsed() {
-        return cumulativeGasUsed;
+    public Wei getGasUsedCumulative() {
+        return Wei.ofWei(cumulativeGasUsed);
     }
 
     public long getConfirmations() {
@@ -113,8 +113,6 @@ public static final class TxErc1155Builder {
         private String to;
         private String contractAddress;
         private String input;
-        private BigInteger gas;
-        private BigInteger gasUsed;
         private long nonce;
         private String blockHash;
         private String tokenID;
@@ -122,8 +120,10 @@ public static final class TxErc1155Builder {
         private String tokenSymbol;
         private String tokenValue;
         private int transactionIndex;
-        private BigInteger gasPrice;
-        private BigInteger cumulativeGasUsed;
+        private Wei gas;
+        private Wei gasUsed;
+        private Wei gasPrice;
+        private Wei cumulativeGasUsed;
         private long confirmations;
 
         private TxErc1155Builder() {}
@@ -163,12 +163,12 @@ public TxErc1155Builder withInput(String input) {
             return this;
         }
 
-        public TxErc1155Builder withGas(BigInteger gas) {
+        public TxErc1155Builder withGas(Wei gas) {
             this.gas = gas;
             return this;
         }
 
-        public TxErc1155Builder withGasUsed(BigInteger gasUsed) {
+        public TxErc1155Builder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
@@ -208,12 +208,12 @@ public TxErc1155Builder withTransactionIndex(int transactionIndex) {
             return this;
         }
 
-        public TxErc1155Builder withGasPrice(BigInteger gasPrice) {
+        public TxErc1155Builder withGasPrice(Wei gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public TxErc1155Builder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
+        public TxErc1155Builder withCumulativeGasUsed(Wei cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
@@ -224,30 +224,38 @@ public TxErc1155Builder withConfirmations(long confirmations) {
         }
 
         public TxErc1155 build() {
-            TxErc1155 txERC721 = new TxErc1155();
-            txERC721.gas = this.gas;
-            txERC721.tokenName = this.tokenName;
-            txERC721.hash = this.hash;
-            txERC721.gasUsed = this.gasUsed;
-            txERC721.nonce = this.nonce;
-            txERC721.from = this.from;
-            txERC721.gasPrice = this.gasPrice;
-            txERC721.contractAddress = this.contractAddress;
-            txERC721.cumulativeGasUsed = this.cumulativeGasUsed;
-            txERC721.tokenID = this.tokenID;
+            TxErc1155 txERC1155 = new TxErc1155();
+            txERC1155.tokenName = this.tokenName;
+            txERC1155.hash = this.hash;
+            txERC1155.nonce = this.nonce;
+            txERC1155.from = this.from;
+            if (this.gas != null) {
+                txERC1155.gas = this.gas.asWei();
+            }
+            if (this.gasUsed != null) {
+                txERC1155.gasUsed = this.gasUsed.asWei();
+            }
+            if (this.gasPrice != null) {
+                txERC1155.gasPrice = this.gasPrice.asWei();
+            }
+            if (this.cumulativeGasUsed != null) {
+                txERC1155.cumulativeGasUsed = this.cumulativeGasUsed.asWei();
+            }
+            txERC1155.contractAddress = this.contractAddress;
+            txERC1155.tokenID = this.tokenID;
             if (this.timeStamp != null) {
-                txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
-                txERC721._timeStamp = this.timeStamp;
+                txERC1155.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
+                txERC1155._timeStamp = this.timeStamp;
             }
-            txERC721.blockNumber = this.blockNumber;
-            txERC721.tokenValue = this.tokenValue;
-            txERC721.transactionIndex = this.transactionIndex;
-            txERC721.to = this.to;
-            txERC721.confirmations = this.confirmations;
-            txERC721.input = this.input;
-            txERC721.blockHash = this.blockHash;
-            txERC721.tokenSymbol = this.tokenSymbol;
-            return txERC721;
+            txERC1155.blockNumber = this.blockNumber;
+            txERC1155.tokenValue = this.tokenValue;
+            txERC1155.transactionIndex = this.transactionIndex;
+            txERC1155.to = this.to;
+            txERC1155.confirmations = this.confirmations;
+            txERC1155.input = this.input;
+            txERC1155.blockHash = this.blockHash;
+            txERC1155.tokenSymbol = this.tokenSymbol;
+            return txERC1155;
         }
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index 197ab5d..751044c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -53,12 +53,12 @@ public int getTransactionIndex() {
         return transactionIndex;
     }
 
-    public BigInteger getGasPrice() {
-        return gasPrice;
+    public Wei getGasPrice() {
+        return Wei.ofWei(gasPrice);
     }
 
-    public BigInteger getCumulativeGasUsed() {
-        return cumulativeGasUsed;
+    public Wei getGasUsedCumulative() {
+        return Wei.ofWei(cumulativeGasUsed);
     }
 
     public long getConfirmations() {
@@ -114,16 +114,16 @@ public static final class TxERC20Builder {
         private BigInteger value;
         private String contractAddress;
         private String input;
-        private BigInteger gas;
-        private BigInteger gasUsed;
+        private Wei gas;
+        private Wei gasUsed;
         private long nonce;
         private String blockHash;
         private String tokenName;
         private String tokenSymbol;
         private String tokenDecimal;
         private int transactionIndex;
-        private BigInteger gasPrice;
-        private BigInteger cumulativeGasUsed;
+        private Wei gasPrice;
+        private Wei cumulativeGasUsed;
         private long confirmations;
 
         private TxERC20Builder() {}
@@ -168,12 +168,12 @@ public TxERC20Builder withInput(String input) {
             return this;
         }
 
-        public TxERC20Builder withGas(BigInteger gas) {
+        public TxERC20Builder withGas(Wei gas) {
             this.gas = gas;
             return this;
         }
 
-        public TxERC20Builder withGasUsed(BigInteger gasUsed) {
+        public TxERC20Builder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
@@ -208,12 +208,12 @@ public TxERC20Builder withTransactionIndex(int transactionIndex) {
             return this;
         }
 
-        public TxERC20Builder withGasPrice(BigInteger gasPrice) {
+        public TxERC20Builder withGasPrice(Wei gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public TxERC20Builder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
+        public TxERC20Builder withCumulativeGasUsed(Wei cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
@@ -225,11 +225,20 @@ public TxERC20Builder withConfirmations(long confirmations) {
 
         public TxErc20 build() {
             TxErc20 txERC20 = new TxErc20();
-            txERC20.gas = this.gas;
             txERC20.tokenName = this.tokenName;
             txERC20.hash = this.hash;
-            txERC20.gasUsed = this.gasUsed;
-            txERC20.cumulativeGasUsed = this.cumulativeGasUsed;
+            if (this.gas != null) {
+                txERC20.gas = this.gas.asWei();
+            }
+            if (this.gasUsed != null) {
+                txERC20.gasUsed = this.gasUsed.asWei();
+            }
+            if (this.gasPrice != null) {
+                txERC20.gasPrice = this.gasPrice.asWei();
+            }
+            if (this.cumulativeGasUsed != null) {
+                txERC20.cumulativeGasUsed = this.cumulativeGasUsed.asWei();
+            }
             txERC20.from = this.from;
             txERC20.tokenSymbol = this.tokenSymbol;
             txERC20.transactionIndex = this.transactionIndex;
@@ -243,7 +252,6 @@ public TxErc20 build() {
             }
             txERC20.blockHash = this.blockHash;
             txERC20.blockNumber = this.blockNumber;
-            txERC20.gasPrice = this.gasPrice;
             txERC20.to = this.to;
             txERC20.input = this.input;
             txERC20.tokenDecimal = this.tokenDecimal;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 644f738..7b59393 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -53,12 +53,12 @@ public int getTransactionIndex() {
         return transactionIndex;
     }
 
-    public BigInteger getGasPrice() {
-        return gasPrice;
+    public Wei getGasPrice() {
+        return Wei.ofWei(gasPrice);
     }
 
-    public BigInteger getCumulativeGasUsed() {
-        return cumulativeGasUsed;
+    public Wei getGasUsedCumulative() {
+        return Wei.ofWei(cumulativeGasUsed);
     }
 
     public long getConfirmations() {
@@ -113,8 +113,6 @@ public static final class TxERC721Builder {
         private String to;
         private String contractAddress;
         private String input;
-        private BigInteger gas;
-        private BigInteger gasUsed;
         private long nonce;
         private String blockHash;
         private String tokenID;
@@ -122,8 +120,10 @@ public static final class TxERC721Builder {
         private String tokenSymbol;
         private String tokenDecimal;
         private int transactionIndex;
-        private BigInteger gasPrice;
-        private BigInteger cumulativeGasUsed;
+        private Wei gas;
+        private Wei gasUsed;
+        private Wei gasPrice;
+        private Wei cumulativeGasUsed;
         private long confirmations;
 
         private TxERC721Builder() {}
@@ -163,12 +163,12 @@ public TxERC721Builder withInput(String input) {
             return this;
         }
 
-        public TxERC721Builder withGas(BigInteger gas) {
+        public TxERC721Builder withGas(Wei gas) {
             this.gas = gas;
             return this;
         }
 
-        public TxERC721Builder withGasUsed(BigInteger gasUsed) {
+        public TxERC721Builder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
@@ -208,12 +208,12 @@ public TxERC721Builder withTransactionIndex(int transactionIndex) {
             return this;
         }
 
-        public TxERC721Builder withGasPrice(BigInteger gasPrice) {
+        public TxERC721Builder withGasPrice(Wei gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public TxERC721Builder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
+        public TxERC721Builder withCumulativeGasUsed(Wei cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
@@ -225,15 +225,23 @@ public TxERC721Builder withConfirmations(long confirmations) {
 
         public TxErc721 build() {
             TxErc721 txERC721 = new TxErc721();
-            txERC721.gas = this.gas;
             txERC721.tokenName = this.tokenName;
             txERC721.hash = this.hash;
-            txERC721.gasUsed = this.gasUsed;
             txERC721.nonce = this.nonce;
             txERC721.from = this.from;
-            txERC721.gasPrice = this.gasPrice;
+            if (this.gas != null) {
+                txERC721.gas = this.gas.asWei();
+            }
+            if (this.gasUsed != null) {
+                txERC721.gasUsed = this.gasUsed.asWei();
+            }
+            if (this.gasPrice != null) {
+                txERC721.gasPrice = this.gasPrice.asWei();
+            }
+            if (this.cumulativeGasUsed != null) {
+                txERC721.cumulativeGasUsed = this.cumulativeGasUsed.asWei();
+            }
             txERC721.contractAddress = this.contractAddress;
-            txERC721.cumulativeGasUsed = this.cumulativeGasUsed;
             txERC721.tokenID = this.tokenID;
             if (this.timeStamp != null) {
                 txERC721.timeStamp = String.valueOf(this.timeStamp.toEpochSecond(ZoneOffset.UTC));
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index fdd89ee..dd74e99 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -90,8 +90,8 @@ public static final class TxInternalBuilder {
         private BigInteger value;
         private String contractAddress;
         private String input;
-        private BigInteger gas;
-        private BigInteger gasUsed;
+        private Wei gas;
+        private Wei gasUsed;
         private String type;
         private String traceId;
         private int isError;
@@ -139,12 +139,12 @@ public TxInternalBuilder withInput(String input) {
             return this;
         }
 
-        public TxInternalBuilder withGas(BigInteger gas) {
+        public TxInternalBuilder withGas(Wei gas) {
             this.gas = gas;
             return this;
         }
 
-        public TxInternalBuilder withGasUsed(BigInteger gasUsed) {
+        public TxInternalBuilder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
@@ -171,9 +171,13 @@ public TxInternalBuilder withErrCode(String errCode) {
 
         public TxInternal build() {
             TxInternal txInternal = new TxInternal();
-            txInternal.gas = this.gas;
             txInternal.hash = this.hash;
-            txInternal.gasUsed = this.gasUsed;
+            if (this.gas != null) {
+                txInternal.gas = this.gas.asWei();
+            }
+            if (this.gasUsed != null) {
+                txInternal.gasUsed = this.gasUsed.asWei();
+            }
             txInternal.traceId = this.traceId;
             txInternal.type = this.type;
             txInternal.from = this.from;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index 004b5e1..038fd4b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -1,6 +1,8 @@
 package io.goodforgod.api.etherscan.model;
 
+import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.math.RoundingMode;
 import java.util.Objects;
 
 /**
@@ -39,25 +41,29 @@ public static Wei ofEther(BigInteger value) {
         return new Wei(value.multiply(BigInteger.valueOf(1_000_000_000_000_000L)));
     }
 
+    public static Wei ofEther(BigDecimal value) {
+        return new Wei(value.multiply(BigDecimal.valueOf(1_000_000_000_000_000L)).toBigInteger());
+    }
+
     // <editor-fold desc="Getters">
     public BigInteger asWei() {
         return result;
     }
 
-    public BigInteger asKwei() {
-        return result.divide(BigInteger.valueOf(1_000));
+    public BigDecimal asKwei() {
+        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000), RoundingMode.HALF_UP);
     }
 
-    public BigInteger asMwei() {
-        return result.divide(BigInteger.valueOf(1_000_000));
+    public BigDecimal asMwei() {
+        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000_000), RoundingMode.HALF_UP);
     }
 
-    public BigInteger asGwei() {
-        return result.divide(BigInteger.valueOf(1_000_000_000));
+    public BigDecimal asGwei() {
+        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000_000_000), RoundingMode.HALF_UP);
     }
 
-    public BigInteger asEther() {
-        return result.divide(BigInteger.valueOf(1_000_000_000_000_000L));
+    public BigDecimal asEther() {
+        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000_000_000_000_000L), RoundingMode.HALF_UP);
     }
     // </editor-fold>
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index a9447ca..c98d5ee 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -1,8 +1,8 @@
 package io.goodforgod.api.etherscan.model.proxy;
 
 import com.google.gson.annotations.Expose;
+import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.util.BasicUtils;
-import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.List;
@@ -35,10 +35,10 @@ public class BlockProxy {
     private String mixHash;
     private String gasUsed;
     @Expose(deserialize = false, serialize = false)
-    private BigInteger _gasUsed;
+    private Wei _gasUsed;
     private String gasLimit;
     @Expose(deserialize = false, serialize = false)
-    private BigInteger _gasLimit;
+    private Wei _gasLimit;
 
     private String sha3Uncles;
     private List<String> uncles;
@@ -108,15 +108,15 @@ public String getMixHash() {
         return mixHash;
     }
 
-    public BigInteger getGasUsed() {
+    public Wei getGasUsed() {
         if (_gasUsed == null && !BasicUtils.isEmpty(gasUsed))
-            _gasUsed = BasicUtils.parseHex(gasUsed);
+            _gasUsed = Wei.ofWei(BasicUtils.parseHex(gasUsed));
         return _gasUsed;
     }
 
-    public BigInteger getGasLimit() {
+    public Wei getGasLimit() {
         if (_gasLimit == null && !BasicUtils.isEmpty(gasLimit))
-            _gasLimit = BasicUtils.parseHex(gasLimit);
+            _gasLimit = Wei.ofWei(BasicUtils.parseHex(gasLimit));
         return _gasLimit;
     }
 
@@ -227,8 +227,8 @@ public static final class BlockProxyBuilder {
         private String extraData;
         private String logsBloom;
         private String mixHash;
-        private BigInteger gasUsed;
-        private BigInteger gasLimit;
+        private Wei gasUsed;
+        private Wei gasLimit;
         private String sha3Uncles;
         private List<String> uncles;
         private String receiptsRoot;
@@ -302,12 +302,12 @@ public BlockProxyBuilder withMixHash(String mixHash) {
             return this;
         }
 
-        public BlockProxyBuilder withGasUsed(BigInteger gasUsed) {
+        public BlockProxyBuilder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
 
-        public BlockProxyBuilder withGasLimit(BigInteger gasLimit) {
+        public BlockProxyBuilder withGasLimit(Wei gasLimit) {
             this.gasLimit = gasLimit;
             return this;
         }
@@ -352,11 +352,9 @@ public BlockProxy build() {
             blockProxy._size = this.size;
             blockProxy.difficulty = this.difficulty;
             if (this.gasLimit != null) {
-                blockProxy.gasLimit = String.valueOf(this.gasLimit);
                 blockProxy._gasLimit = this.gasLimit;
             }
             if (this.gasUsed != null) {
-                blockProxy.gasUsed = String.valueOf(this.gasUsed);
                 blockProxy._gasUsed = this.gasUsed;
             }
             blockProxy.size = String.valueOf(this.size);
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index 61a7942..2b616c3 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -2,8 +2,8 @@
 
 import com.google.gson.annotations.Expose;
 import io.goodforgod.api.etherscan.model.Log;
+import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.util.BasicUtils;
-import java.math.BigInteger;
 import java.util.List;
 
 /**
@@ -25,10 +25,10 @@ public class ReceiptProxy {
     private Long _transactionIndex;
     private String gasUsed;
     @Expose(serialize = false, deserialize = false)
-    private BigInteger _gasUsed;
+    private Wei _gasUsed;
     private String cumulativeGasUsed;
     @Expose(serialize = false, deserialize = false)
-    private BigInteger _cumulativeGasUsed;
+    private Wei _cumulativeGasUsed;
     private String contractAddress;
 
     private List<Log> logs;
@@ -69,15 +69,15 @@ public Long getTransactionIndex() {
         return _transactionIndex;
     }
 
-    public BigInteger getGasUsed() {
+    public Wei getGasUsed() {
         if (_gasUsed == null && !BasicUtils.isEmpty(gasUsed))
-            _gasUsed = BasicUtils.parseHex(gasUsed);
+            _gasUsed = Wei.ofWei(BasicUtils.parseHex(gasUsed));
         return _gasUsed;
     }
 
-    public BigInteger getCumulativeGasUsed() {
+    public Wei getCumulativeGasUsed() {
         if (_cumulativeGasUsed == null && !BasicUtils.isEmpty(cumulativeGasUsed))
-            _cumulativeGasUsed = BasicUtils.parseHex(cumulativeGasUsed);
+            _cumulativeGasUsed = Wei.ofWei(BasicUtils.parseHex(cumulativeGasUsed));
         return _cumulativeGasUsed;
     }
 
@@ -165,8 +165,8 @@ public static final class ReceiptProxyBuilder {
         private String blockHash;
         private String transactionHash;
         private Long transactionIndex;
-        private BigInteger gasUsed;
-        private BigInteger cumulativeGasUsed;
+        private Wei gasUsed;
+        private Wei cumulativeGasUsed;
         private String contractAddress;
         private List<Log> logs;
         private String logsBloom;
@@ -208,12 +208,12 @@ public ReceiptProxyBuilder withTransactionIndex(Long transactionIndex) {
             return this;
         }
 
-        public ReceiptProxyBuilder withGasUsed(BigInteger gasUsed) {
+        public ReceiptProxyBuilder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
 
-        public ReceiptProxyBuilder withCumulativeGasUsed(BigInteger cumulativeGasUsed) {
+        public ReceiptProxyBuilder withCumulativeGasUsed(Wei cumulativeGasUsed) {
             this.cumulativeGasUsed = cumulativeGasUsed;
             return this;
         }
@@ -244,13 +244,11 @@ public ReceiptProxy build() {
             receiptProxy.root = this.root;
             receiptProxy.contractAddress = this.contractAddress;
             if (this.gasUsed != null) {
-                receiptProxy.gasUsed = String.valueOf(this.gasUsed);
                 receiptProxy._gasUsed = this.gasUsed;
             }
             receiptProxy.logs = this.logs;
             receiptProxy.to = this.to;
             if (this.cumulativeGasUsed != null) {
-                receiptProxy.cumulativeGasUsed = String.valueOf(this.cumulativeGasUsed);
                 receiptProxy._cumulativeGasUsed = this.cumulativeGasUsed;
             }
             receiptProxy.transactionIndex = String.valueOf(this.transactionIndex);
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index 0ca7f3a..b2b412b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -1,8 +1,8 @@
 package io.goodforgod.api.etherscan.model.proxy;
 
 import com.google.gson.annotations.Expose;
+import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.util.BasicUtils;
-import java.math.BigInteger;
 
 /**
  * @author GoodforGod
@@ -26,10 +26,10 @@ public class TxProxy {
     private String value;
     private String gas;
     @Expose(deserialize = false, serialize = false)
-    private BigInteger _gas;
+    private Wei _gas;
     private String gasPrice;
     @Expose(deserialize = false, serialize = false)
-    private BigInteger _gasPrice;
+    private Wei _gasPrice;
     private String blockHash;
     private String blockNumber;
     @Expose(deserialize = false, serialize = false)
@@ -56,9 +56,9 @@ public String getFrom() {
         return from;
     }
 
-    public BigInteger getGas() {
+    public Wei getGas() {
         if (_gas == null && !BasicUtils.isEmpty(gas))
-            _gas = BasicUtils.parseHex(gas);
+            _gas = Wei.ofWei(BasicUtils.parseHex(gas));
         return _gas;
     }
 
@@ -88,9 +88,9 @@ public String getValue() {
         return value;
     }
 
-    public BigInteger getGasPrice() {
+    public Wei getGasPrice() {
         if (_gasPrice == null && !BasicUtils.isEmpty(gasPrice))
-            _gasPrice = BasicUtils.parseHex(gasPrice);
+            _gasPrice = Wei.ofWei(BasicUtils.parseHex(gasPrice));
         return _gasPrice;
     }
 
@@ -182,8 +182,8 @@ public static final class TxProxyBuilder {
         private String r;
         private Long nonce;
         private String value;
-        private BigInteger gas;
-        private BigInteger gasPrice;
+        private Wei gas;
+        private Wei gasPrice;
         private String blockHash;
         private Long blockNumber;
 
@@ -239,12 +239,12 @@ public TxProxyBuilder withValue(String value) {
             return this;
         }
 
-        public TxProxyBuilder withGas(BigInteger gas) {
+        public TxProxyBuilder withGas(Wei gas) {
             this.gas = gas;
             return this;
         }
 
-        public TxProxyBuilder withGasPrice(BigInteger gasPrice) {
+        public TxProxyBuilder withGasPrice(Wei gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
@@ -263,7 +263,6 @@ public TxProxy build() {
             TxProxy txProxy = new TxProxy();
             txProxy.input = this.input;
             if (this.gas != null) {
-                txProxy.gas = String.valueOf(this.gas);
                 txProxy._gas = this.gas;
             }
             txProxy.s = this.s;
@@ -281,7 +280,6 @@ public TxProxy build() {
             txProxy._blockNumber = this.blockNumber;
             txProxy.hash = this.hash;
             if (this.gasPrice != null) {
-                txProxy.gasPrice = String.valueOf(this.gasPrice);
                 txProxy._gasPrice = this.gasPrice;
             }
             return txProxy;

From 1416a232e4a8c13b46e6cd7bf571f063b9bb0da0 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 00:06:23 +0300
Subject: [PATCH 39/67] [2.0.0-SNAPSHOT] RequestQueueManager static consts ->
 static method to produce uniq request queue managers Tests manager provision
 fixed

---
 .../api/etherscan/AccountAPIProvider.java     |  9 +++--
 .../api/etherscan/EthScanAPIBuilder.java      | 17 ++++++---
 .../manager/RequestQueueManager.java          | 27 ++++++++++---
 .../goodforgod/api/etherscan/ApiRunner.java   |  8 +---
 .../api/etherscan/EtherScanAPITests.java      |  1 -
 .../account/AccountTxErc20Tests.java          |  4 +-
 .../account/AccountTxRc1155TokenTests.java    |  2 +-
 .../account/AccountTxRc721TokenTests.java     |  2 +-
 .../etherscan/account/AccountTxsTests.java    |  4 +-
 .../etherscan/model/ModelBuilderTests.java    | 38 +++++++++----------
 .../etherscan/proxy/ProxyBlockApiTests.java   | 17 ++-------
 11 files changed, 69 insertions(+), 60 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index e5b6bd9..08e9dd5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -84,8 +84,9 @@ public TokenBalance balance(String address, String contract) throws EtherScanExc
     @NotNull
     @Override
     public List<Balance> balances(List<String> addresses) throws EtherScanException {
-        if (BasicUtils.isEmpty(addresses))
+        if (BasicUtils.isEmpty(addresses)) {
             return Collections.emptyList();
+        }
 
         BasicUtils.validateAddresses(addresses);
 
@@ -96,13 +97,15 @@ public List<Balance> balances(List<String> addresses) throws EtherScanException
         for (final List<String> batch : addressesAsBatches) {
             final String urlParams = ACT_BALANCE_MULTI_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + toAddressParam(batch);
             final BalanceResponseTO response = getRequest(urlParams, BalanceResponseTO.class);
-            if (response.getStatus() != 1)
+            if (response.getStatus() != 1) {
                 throw new EtherScanResponseException(response);
+            }
 
-            if (!BasicUtils.isEmpty(response.getResult()))
+            if (!BasicUtils.isEmpty(response.getResult())) {
                 balances.addAll(response.getResult().stream()
                         .map(r -> new Balance(r.getAccount(), Wei.ofWei(new BigInteger(r.getBalance()))))
                         .collect(Collectors.toList()));
+            }
         }
 
         return balances;
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index 57aeeae..dad9c50 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -27,8 +27,8 @@ final class EthScanAPIBuilder implements EtherScanAPI.Builder {
     private final Gson gson = new GsonConfiguration().builder().create();
 
     private String apiKey = DEFAULT_KEY;
+    private RequestQueueManager queueManager;
     private EthNetwork ethNetwork = EthNetworks.MAINNET;
-    private RequestQueueManager queueManager = RequestQueueManager.ANONYMOUS;
     private Supplier<EthHttpClient> ethHttpClientSupplier = DEFAULT_SUPPLIER;
     private Supplier<Converter> converterSupplier = () -> new Converter() {
 
@@ -49,9 +49,6 @@ public EtherScanAPI.Builder withApiKey(@NotNull String apiKey) {
             throw new EtherScanKeyException("API key can not be null or empty");
 
         this.apiKey = apiKey;
-        if (!DEFAULT_KEY.equals(apiKey)) {
-            queueManager = RequestQueueManager.UNLIMITED;
-        }
         return this;
     }
 
@@ -92,6 +89,16 @@ public EtherScanAPI.Builder withConverter(@NotNull Supplier<Converter> converter
 
     @Override
     public @NotNull EtherScanAPI build() {
-        return new EtherScanAPIProvider(apiKey, ethNetwork, queueManager, ethHttpClientSupplier.get(), converterSupplier.get());
+        RequestQueueManager requestQueueManager;
+        if (queueManager != null) {
+            requestQueueManager = queueManager;
+        } else if (DEFAULT_KEY.equals(apiKey)) {
+            requestQueueManager = RequestQueueManager.anonymous();
+        } else {
+            requestQueueManager = RequestQueueManager.planFree();
+        }
+
+        return new EtherScanAPIProvider(apiKey, ethNetwork, requestQueueManager, ethHttpClientSupplier.get(),
+                converterSupplier.get());
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index 4d6b586..449daca 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -16,18 +16,33 @@ public interface RequestQueueManager extends AutoCloseable {
     /**
      * Is used by default when no API KEY is provided
      */
-    RequestQueueManager ANONYMOUS = new SemaphoreRequestQueueManager(1, Duration.ofMillis(5015L));
+    static RequestQueueManager anonymous() {
+        return new SemaphoreRequestQueueManager(1, Duration.ofMillis(5005L));
+    }
 
     /**
      * Is available for all registered free API KEYs
      * <a href="https://docs.etherscan.io/getting-started/viewing-api-usage-statistics">Free API KEY</a>
      */
-    RequestQueueManager FREE_PLAN = new SemaphoreRequestQueueManager(5, Duration.ofMillis(1015L));
-    RequestQueueManager STANDARD_PLAN = new SemaphoreRequestQueueManager(10, Duration.ofMillis(1015L));
-    RequestQueueManager ADVANCED_PLAN = new SemaphoreRequestQueueManager(20, Duration.ofMillis(1015L));
-    RequestQueueManager PROFESSIONAL_PLAN = new SemaphoreRequestQueueManager(30, Duration.ofMillis(1015L));
+    static RequestQueueManager planFree() {
+        return new SemaphoreRequestQueueManager(5, Duration.ofMillis(1005L));
+    }
 
-    RequestQueueManager UNLIMITED = new FakeRequestQueueManager();
+    static RequestQueueManager planStandard() {
+        return new SemaphoreRequestQueueManager(10, Duration.ofMillis(1005L));
+    }
+
+    static RequestQueueManager planAdvanced() {
+        return new SemaphoreRequestQueueManager(20, Duration.ofMillis(1005L));
+    }
+
+    static RequestQueueManager planProfessional() {
+        return new SemaphoreRequestQueueManager(30, Duration.ofMillis(1005L));
+    }
+
+    static RequestQueueManager unlimited() {
+        return new FakeRequestQueueManager();
+    }
 
     /**
      * Waits in queue for chance to take turn
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index d28a8e0..4b52c00 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -20,8 +20,8 @@ public class ApiRunner extends Assertions {
                 .orElse(DEFAULT_KEY);
 
         final RequestQueueManager queueManager = (DEFAULT_KEY.equals(API_KEY))
-                ? RequestQueueManager.ANONYMOUS
-                : RequestQueueManager.FREE_PLAN;
+                ? RequestQueueManager.anonymous()
+                : RequestQueueManager.planFree();
 
         API = EtherScanAPI.builder()
                 .withApiKey(ApiRunner.API_KEY)
@@ -30,10 +30,6 @@ public class ApiRunner extends Assertions {
                 .build();
     }
 
-    public static String getApiKey() {
-        return API_KEY;
-    }
-
     public static EtherScanAPI getApi() {
         return API;
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
index c50b03a..36e23ec 100644
--- a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
@@ -68,7 +68,6 @@ void timeout() throws InterruptedException {
         TimeUnit.SECONDS.sleep(5);
         Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300), Duration.ofMillis(300));
         EtherScanAPI api = EtherScanAPI.builder()
-                .withApiKey(getApiKey())
                 .withNetwork(() -> URI.create("https://api-unknown.etherscan.io/api"))
                 .withHttpClient(supplier)
                 .build();
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
index 928b2e3..b26bcee 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
@@ -18,7 +18,7 @@ void correct() {
         assertNotNull(txs);
         assertEquals(3, txs.size());
         assertTxs(txs);
-        assertNotEquals(0, txs.get(0).getGasPrice());
+        assertNotEquals(0, txs.get(0).getGasPrice().asWei().intValue());
         assertNotEquals(-1, txs.get(0).getNonce());
 
         assertNotNull(txs.get(0).toString());
@@ -71,7 +71,7 @@ private void assertTxs(List<TxErc20> txs) {
             assertNotNull(tx.getTokenDecimal());
             assertNotEquals(-1, (tx.getConfirmations()));
             assertNotNull(tx.getGasUsed());
-            assertNotEquals(-1, tx.getCumulativeGasUsed());
+            assertNotEquals(-1, tx.getGasUsedCumulative());
             assertNotEquals(-1, tx.getTransactionIndex());
         }
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
index 0430dc8..f8cae43 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
@@ -75,7 +75,7 @@ private void asserTx(TxErc1155 tx) {
         assertNotNull(tx.getTokenValue());
         assertNotEquals(-1, (tx.getConfirmations()));
         assertNotNull(tx.getGasUsed());
-        assertNotEquals(-1, tx.getCumulativeGasUsed());
+        assertNotEquals(-1, tx.getGasUsedCumulative());
         assertNotEquals(-1, tx.getTransactionIndex());
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
index 9a5a322..ca86256 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
@@ -73,7 +73,7 @@ private void assertTxs(List<TxErc721> txs) {
             assertNotNull(tx.getTokenDecimal());
             assertNotEquals(-1, (tx.getConfirmations()));
             assertNotNull(tx.getGasUsed());
-            assertNotEquals(-1, tx.getCumulativeGasUsed());
+            assertNotEquals(-1, tx.getGasUsedCumulative());
             assertNotEquals(-1, tx.getTransactionIndex());
         }
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
index 3ee8ad1..653f62a 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
@@ -24,7 +24,7 @@ void correct() {
         assertNotNull(txs.get(0).getTo());
         assertNotNull(txs.get(0).getBlockHash());
         assertNotNull(txs.get(0).getGas());
-        assertNotNull(txs.get(0).getCumulativeGasUsed());
+        assertNotNull(txs.get(0).getGasUsedCumulative());
         assertNotNull(txs.get(0).getGasPrice());
         assertNotNull(txs.get(0).getValue());
         assertNotNull(txs.get(0).getContractAddress());
@@ -75,7 +75,7 @@ private void assertTxs(List<Tx> txs) {
             assertNotEquals(-1, (tx.getNonce()));
             assertNotEquals(0, (tx.getTransactionIndex()));
             assertNotEquals(0, tx.getConfirmations());
-            assertNotNull(tx.getTxreceipt_status());
+            assertNotNull(tx.getTxReceiptStatus());
         }
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index 9a7e426..806865d 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -132,12 +132,12 @@ void txBuilder() {
                 .withBlockNumber(1L)
                 .withConfirmations(1L)
                 .withContractAddress("1")
-                .withCumulativeGasUsed(BigInteger.ONE)
                 .withFrom("1")
                 .withTo("1")
-                .withGas(BigInteger.ONE)
-                .withGasPrice(BigInteger.ONE)
-                .withGasUsed(BigInteger.ONE)
+                .withCumulativeGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasPrice(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
                 .withHash("1")
                 .withInput("1")
                 .withIsError("1")
@@ -145,7 +145,7 @@ void txBuilder() {
                 .withTimeStamp(timestamp)
                 .withValue(BigInteger.ONE)
                 .withTransactionIndex(1)
-                .withTxreceiptStatus("1")
+                .withTxReceiptStatus("1")
                 .build();
 
         assertNotNull(value);
@@ -162,12 +162,12 @@ void txErc20Builder() {
                 .withBlockNumber(1L)
                 .withConfirmations(1L)
                 .withContractAddress("1")
-                .withCumulativeGasUsed(BigInteger.ONE)
                 .withFrom("1")
                 .withTo("1")
-                .withGas(BigInteger.ONE)
-                .withGasPrice(BigInteger.ONE)
-                .withGasUsed(BigInteger.ONE)
+                .withCumulativeGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasPrice(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
                 .withHash("1")
                 .withInput("1")
                 .withTokenName("1")
@@ -192,12 +192,12 @@ void txErc721Builder() {
                 .withBlockNumber(1L)
                 .withConfirmations(1L)
                 .withContractAddress("1")
-                .withCumulativeGasUsed(BigInteger.ONE)
                 .withFrom("1")
                 .withTo("1")
-                .withGas(BigInteger.ONE)
-                .withGasPrice(BigInteger.ONE)
-                .withGasUsed(BigInteger.ONE)
+                .withCumulativeGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasPrice(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
                 .withHash("1")
                 .withInput("1")
                 .withTokenName("1")
@@ -222,12 +222,12 @@ void txErc1155Builder() {
                 .withBlockNumber(1L)
                 .withConfirmations(1L)
                 .withContractAddress("1")
-                .withCumulativeGasUsed(BigInteger.ONE)
                 .withFrom("1")
                 .withTo("1")
-                .withGas(BigInteger.ONE)
-                .withGasPrice(BigInteger.ONE)
-                .withGasUsed(BigInteger.ONE)
+                .withCumulativeGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasPrice(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
                 .withHash("1")
                 .withInput("1")
                 .withTokenName("1")
@@ -253,8 +253,8 @@ void txInternalBuilder() {
                 .withFrom("1")
                 .withTo("1")
                 .withValue(BigInteger.ONE)
-                .withGas(BigInteger.ONE)
-                .withGasUsed(BigInteger.ONE)
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
                 .withHash("1")
                 .withInput("1")
                 .withTimeStamp(timestamp)
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
index 874ccc0..363d5a2 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
@@ -1,9 +1,6 @@
 package io.goodforgod.api.etherscan.proxy;
 
 import io.goodforgod.api.etherscan.ApiRunner;
-import io.goodforgod.api.etherscan.EthNetworks;
-import io.goodforgod.api.etherscan.EtherScanAPI;
-import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
 import java.util.Optional;
 import org.junit.jupiter.api.Test;
@@ -14,17 +11,9 @@
  */
 class ProxyBlockApiTests extends ApiRunner {
 
-    private final EtherScanAPI api;
-
-    ProxyBlockApiTests() {
-        final RequestQueueManager queueManager = RequestQueueManager.ANONYMOUS;
-        this.api = EtherScanAPI.builder().withApiKey(getApiKey()).withNetwork(EthNetworks.MAINNET).withQueue(queueManager)
-                .build();
-    }
-
     @Test
     void correct() {
-        Optional<BlockProxy> block = api.proxy().block(5120);
+        Optional<BlockProxy> block = getApi().proxy().block(5120);
         assertTrue(block.isPresent());
         BlockProxy proxy = block.get();
         assertNotNull(proxy.getHash());
@@ -57,13 +46,13 @@ void correct() {
 
     @Test
     void correctParamWithEmptyExpectedResult() {
-        Optional<BlockProxy> block = api.proxy().block(99999999999L);
+        Optional<BlockProxy> block = getApi().proxy().block(99999999999L);
         assertFalse(block.isPresent());
     }
 
     @Test
     void correctParamNegativeNo() {
-        Optional<BlockProxy> block = api.proxy().block(-1);
+        Optional<BlockProxy> block = getApi().proxy().block(-1);
         assertTrue(block.isPresent());
         assertNotNull(block.get().getHash());
     }

From 14ccb53db6d1b6e28a273dd1dbb79ba5a8123986 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 00:19:41 +0300
Subject: [PATCH 40/67] [2.0.0-SNAPSHOT] Test asserts fixed Log contract
 improved Tests reinforced

---
 .../api/etherscan/model/EthSupply.java        |  26 ++++-
 .../goodforgod/api/etherscan/model/Log.java   |  23 ++--
 .../account/AccountTxErc20Tests.java          |   2 +-
 .../account/AccountTxRc1155TokenTests.java    |   4 +-
 .../account/AccountTxRc721TokenTests.java     |   4 +-
 .../etherscan/model/ModelBuilderTests.java    | 104 +++++++++++++++++-
 .../StatisticTokenSupplyApiTests.java         |   2 +-
 7 files changed, 138 insertions(+), 27 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
index f967360..344e754 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
@@ -4,8 +4,6 @@
 import java.util.Objects;
 
 /**
- * Please Add Description Here.
- *
  * @author Anton Kurako (GoodforGod)
  * @since 14.05.2023
  */
@@ -100,10 +98,26 @@ public EthSupplyBuilder withWithdrawnTotal(Wei withdrawnTotal) {
 
         public EthSupply build() {
             EthSupply ethSupply = new EthSupply();
-            ethSupply.BurntFees = this.burntFees.toString();
-            ethSupply.Eth2Staking = this.eth2Staking.toString();
-            ethSupply.EthSupply = this.ethSupply.toString();
-            ethSupply.WithdrawnTotal = this.withdrawnTotal.toString();
+            if (this.burntFees != null) {
+                ethSupply.BurntFees = this.burntFees.toString();
+            } else {
+                ethSupply.BurntFees = BigInteger.ZERO.toString();
+            }
+            if (this.eth2Staking != null) {
+                ethSupply.Eth2Staking = this.eth2Staking.toString();
+            } else {
+                ethSupply.Eth2Staking = BigInteger.ZERO.toString();
+            }
+            if (this.ethSupply != null) {
+                ethSupply.EthSupply = this.ethSupply.toString();
+            } else {
+                ethSupply.EthSupply = BigInteger.ZERO.toString();
+            }
+            if (this.withdrawnTotal != null) {
+                ethSupply.WithdrawnTotal = this.withdrawnTotal.toString();
+            } else {
+                ethSupply.WithdrawnTotal = BigInteger.ZERO.toString();
+            }
             return ethSupply;
         }
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index 07e652f..8e14b16 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -2,7 +2,6 @@
 
 import com.google.gson.annotations.Expose;
 import io.goodforgod.api.etherscan.util.BasicUtils;
-import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.List;
@@ -28,10 +27,10 @@ public class Log {
     private String data;
     private String gasPrice;
     @Expose(deserialize = false, serialize = false)
-    private BigInteger _gasPrice;
+    private Wei _gasPrice;
     private String gasUsed;
     @Expose(deserialize = false, serialize = false)
-    private BigInteger _gasUsed;
+    private Wei _gasUsed;
     private List<String> topics;
     private String logIndex;
     @Expose(deserialize = false, serialize = false)
@@ -93,17 +92,17 @@ public String getData() {
         return data;
     }
 
-    public BigInteger getGasPrice() {
+    public Wei getGasPrice() {
         if (!BasicUtils.isEmpty(gasPrice)) {
-            _gasPrice = BasicUtils.parseHex(gasPrice);
+            _gasPrice = Wei.ofWei(BasicUtils.parseHex(gasPrice));
         }
 
         return _gasPrice;
     }
 
-    public BigInteger getGasUsed() {
+    public Wei getGasUsed() {
         if (!BasicUtils.isEmpty(gasUsed)) {
-            _gasUsed = BasicUtils.parseHex(gasUsed);
+            _gasUsed = Wei.ofWei(BasicUtils.parseHex(gasUsed));
         }
 
         return _gasUsed;
@@ -172,8 +171,8 @@ public static final class LogBuilder {
         private Long transactionIndex;
         private LocalDateTime timeStamp;
         private String data;
-        private BigInteger gasPrice;
-        private BigInteger gasUsed;
+        private Wei gasPrice;
+        private Wei gasUsed;
         private List<String> topics;
         private Long logIndex;
 
@@ -209,12 +208,12 @@ public LogBuilder withData(String data) {
             return this;
         }
 
-        public LogBuilder withGasPrice(BigInteger gasPrice) {
+        public LogBuilder withGasPrice(Wei gasPrice) {
             this.gasPrice = gasPrice;
             return this;
         }
 
-        public LogBuilder withGasUsed(BigInteger gasUsed) {
+        public LogBuilder withGasUsed(Wei gasUsed) {
             this.gasUsed = gasUsed;
             return this;
         }
@@ -233,7 +232,6 @@ public Log build() {
             Log log = new Log();
             log.address = this.address;
             if (this.gasPrice != null) {
-                log.gasPrice = String.valueOf(this.gasPrice);
                 log._gasPrice = this.gasPrice;
             }
             log._logIndex = this.logIndex;
@@ -246,7 +244,6 @@ public Log build() {
             }
             log.data = this.data;
             if (this.gasUsed != null) {
-                log.gasUsed = String.valueOf(this.gasUsed);
                 log._gasUsed = this.gasUsed;
             }
             log.logIndex = String.valueOf(this.logIndex);
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
index b26bcee..4239bcd 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxErc20Tests.java
@@ -71,7 +71,7 @@ private void assertTxs(List<TxErc20> txs) {
             assertNotNull(tx.getTokenDecimal());
             assertNotEquals(-1, (tx.getConfirmations()));
             assertNotNull(tx.getGasUsed());
-            assertNotEquals(-1, tx.getGasUsedCumulative());
+            assertNotEquals(-1, tx.getGasUsedCumulative().asWei().intValue());
             assertNotEquals(-1, tx.getTransactionIndex());
         }
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
index f8cae43..d8cbb73 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc1155TokenTests.java
@@ -18,7 +18,7 @@ void correct() {
         assertNotNull(txs);
         assertFalse(txs.isEmpty());
         assertTxs(txs);
-        assertNotEquals(0, txs.get(0).getGasPrice());
+        assertNotEquals(0, txs.get(0).getGasPrice().asWei().intValue());
         assertNotEquals(-1, txs.get(0).getNonce());
 
         assertNotNull(txs.get(0).toString());
@@ -75,7 +75,7 @@ private void asserTx(TxErc1155 tx) {
         assertNotNull(tx.getTokenValue());
         assertNotEquals(-1, (tx.getConfirmations()));
         assertNotNull(tx.getGasUsed());
-        assertNotEquals(-1, tx.getGasUsedCumulative());
+        assertNotEquals(-1, tx.getGasUsedCumulative().asWei().intValue());
         assertNotEquals(-1, tx.getTransactionIndex());
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
index ca86256..6c61a4c 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxRc721TokenTests.java
@@ -18,7 +18,7 @@ void correct() {
         assertNotNull(txs);
         assertEquals(16, txs.size());
         assertTxs(txs);
-        assertNotEquals(0, txs.get(0).getGasPrice());
+        assertNotEquals(0, txs.get(0).getGasPrice().asWei().intValue());
         assertNotEquals(-1, txs.get(0).getNonce());
 
         assertNotNull(txs.get(0).toString());
@@ -73,7 +73,7 @@ private void assertTxs(List<TxErc721> txs) {
             assertNotNull(tx.getTokenDecimal());
             assertNotEquals(-1, (tx.getConfirmations()));
             assertNotNull(tx.getGasUsed());
-            assertNotEquals(-1, tx.getGasUsedCumulative());
+            assertNotEquals(-1, tx.getGasUsedCumulative().asWei().intValue());
             assertNotEquals(-1, tx.getTransactionIndex());
         }
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index 806865d..9018ec8 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -1,8 +1,12 @@
 package io.goodforgod.api.etherscan.model;
 
+import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
+import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
+import io.goodforgod.api.etherscan.model.proxy.TxProxy;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.time.LocalDateTime;
+import java.util.Arrays;
 import java.util.Collections;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -84,8 +88,8 @@ void logBuilder() {
                 .withAddress("1")
                 .withBlockNumber(1L)
                 .withData("1")
-                .withGasPrice(BigInteger.ONE)
-                .withGasUsed(BigInteger.ONE)
+                .withGasPrice(Wei.ofWei(1))
+                .withGasUsed(Wei.ofWei(1))
                 .withLogIndex(1L)
                 .withTimeStamp(timestamp)
                 .withTransactionHash("1")
@@ -268,4 +272,100 @@ void txInternalBuilder() {
         assertEquals("1", value.getTo());
         assertEquals("1", value.getFrom());
     }
+
+    @Test
+    void ethSupplyBuilder() {
+        EthSupply value = EthSupply.builder()
+                .withBurntFees(Wei.ofWei(1))
+                .withEth2Staking(Wei.ofWei(1))
+                .withEthSupply(Wei.ofWei(1))
+                .withWithdrawnTotal(Wei.ofWei(1))
+                .build();
+
+        assertNotNull(value);
+        assertEquals(BigInteger.valueOf(1), value.getTotal().asWei());
+
+        EthSupply valueEmpty = EthSupply.builder()
+                .build();
+        assertNotNull(valueEmpty);
+        assertEquals(BigInteger.ZERO, valueEmpty.getTotal().asWei());
+    }
+
+    @Test
+    void receiptProxyBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        ReceiptProxy value = ReceiptProxy.builder()
+                .withBlockHash("1")
+                .withBlockNumber(1L)
+                .withContractAddress("1")
+                .withCumulativeGasUsed(Wei.ofWei(1))
+                .withFrom("1")
+                .withTo("1")
+                .withGasUsed(Wei.ofWei(1))
+                .withRoot("1")
+                .withLogsBloom("1")
+                .withTransactionHash("1")
+                .withTransactionIndex(1L)
+                .withLogs(Arrays.asList(Log.builder()
+                        .withTopics(Arrays.asList("1"))
+                        .withTransactionIndex(1L)
+                        .withTransactionHash("1")
+                        .withTimeStamp(timestamp)
+                        .withLogIndex(1L)
+                        .withGasUsed(Wei.ofWei(1))
+                        .withGasPrice(Wei.ofWei(1))
+                        .withData("1")
+                        .withAddress("1")
+                        .build()))
+                .build();
+
+        assertNotNull(value);
+        assertEquals(BigInteger.valueOf(1), value.getGasUsed().asWei());
+    }
+
+    @Test
+    void blockProxyBuilder() {
+        LocalDateTime timestamp = LocalDateTime.now();
+        BlockProxy value = BlockProxy.builder()
+                .withGasUsed(Wei.ofWei(1))
+                .withLogsBloom("1")
+                .withDifficulty("1")
+                .withExtraData("1")
+                .withGasLimit(Wei.ofWei(1))
+                .withHash("1")
+                .withMiner("1")
+                .withMixHash("1")
+                .withNonce("1")
+                .withNumber(1L)
+                .withParentHash("1")
+                .withReceiptsRoot("1")
+                .withSha3Uncles("1")
+                .withSize(1L)
+                .withStateRoot("1")
+                .withTimestamp(timestamp)
+                .withTotalDifficulty("1")
+                .withTransactionsRoot("1")
+                .withUncles(Arrays.asList("1"))
+                .withTransactions(Arrays.asList(TxProxy.builder()
+                        .withBlockHash("1")
+                        .withBlockNumber(1L)
+                        .withFrom("1")
+                        .withGas(Wei.ofWei(1))
+                        .withGasPrice(Wei.ofWei(1))
+                        .withHash("1")
+                        .withInput("1")
+                        .withNonce(1L)
+                        .withR("1")
+                        .withS("1")
+                        .withTo("1")
+                        .withTransactionIndex(1L)
+                        .withV("1")
+                        .withValue("1")
+                        .withV("1")
+                        .build()))
+                .build();
+
+        assertNotNull(value);
+        assertEquals(BigInteger.valueOf(1), value.getGasUsed().asWei());
+    }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
index b21b3b3..6eff846 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticTokenSupplyApiTests.java
@@ -16,7 +16,7 @@ class StatisticTokenSupplyApiTests extends ApiRunner {
     void correct() {
         Wei supply = getApi().stats().supply("0x57d90b64a1a57749b0f932f1a3395792e12e7055");
         assertNotNull(supply);
-        assertNotEquals(BigInteger.ZERO, supply);
+        assertNotEquals(BigInteger.ZERO, supply.asWei());
     }
 
     @Test

From bf30d9a2df7567a86ae494cbbb7ba62b49a2dfcb Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 00:27:58 +0300
Subject: [PATCH 41/67] [2.0.0-SNAPSHOT] 1005L->1015L

---
 .../api/etherscan/manager/RequestQueueManager.java     | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index 449daca..0f36b23 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -17,7 +17,7 @@ public interface RequestQueueManager extends AutoCloseable {
      * Is used by default when no API KEY is provided
      */
     static RequestQueueManager anonymous() {
-        return new SemaphoreRequestQueueManager(1, Duration.ofMillis(5005L));
+        return new SemaphoreRequestQueueManager(1, Duration.ofMillis(5015L));
     }
 
     /**
@@ -25,19 +25,19 @@ static RequestQueueManager anonymous() {
      * <a href="https://docs.etherscan.io/getting-started/viewing-api-usage-statistics">Free API KEY</a>
      */
     static RequestQueueManager planFree() {
-        return new SemaphoreRequestQueueManager(5, Duration.ofMillis(1005L));
+        return new SemaphoreRequestQueueManager(5, Duration.ofMillis(1015L));
     }
 
     static RequestQueueManager planStandard() {
-        return new SemaphoreRequestQueueManager(10, Duration.ofMillis(1005L));
+        return new SemaphoreRequestQueueManager(10, Duration.ofMillis(1015L));
     }
 
     static RequestQueueManager planAdvanced() {
-        return new SemaphoreRequestQueueManager(20, Duration.ofMillis(1005L));
+        return new SemaphoreRequestQueueManager(20, Duration.ofMillis(1015L));
     }
 
     static RequestQueueManager planProfessional() {
-        return new SemaphoreRequestQueueManager(30, Duration.ofMillis(1005L));
+        return new SemaphoreRequestQueueManager(30, Duration.ofMillis(1015L));
     }
 
     static RequestQueueManager unlimited() {

From 3a3e409ac48b4d039e9ef2077e98e12ca189293d Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 00:41:05 +0300
Subject: [PATCH 42/67] [2.0.0-SNAPSHOT] Tests reinforced

---
 .../api/etherscan/model/GasEstimate.java      |  4 +--
 .../etherscan/model/ModelBuilderTests.java    | 31 +++++++++++++++++++
 2 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java b/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
index 7f1e61d..198e53c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
@@ -40,8 +40,6 @@ public int hashCode() {
 
     @Override
     public String toString() {
-        return "GasEstimate{" +
-                "duration=" + duration +
-                '}';
+        return duration.toString();
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index 9018ec8..464b379 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -79,6 +79,18 @@ void gasOracleBuilder() {
 
         assertNotNull(value);
         assertEquals(Wei.ofWei(1000000000), value.getFastGasPriceInWei());
+
+        GasOracle value2 = GasOracle.builder()
+                .withFastGasPrice(Wei.ofWei(1000000000))
+                .withProposeGasPrice(Wei.ofWei(1000000000))
+                .withSafeGasPrice(Wei.ofWei(1000000000))
+                .withGasUsedRatio(Collections.singletonList(new BigDecimal(1)))
+                .withLastBlock(1L)
+                .withSuggestBaseFee(1.0)
+                .build();
+        assertEquals(value, value2);
+        assertEquals(value.hashCode(), value2.hashCode());
+        assertEquals(value.toString(), value2.toString());
     }
 
     @Test
@@ -289,6 +301,16 @@ void ethSupplyBuilder() {
                 .build();
         assertNotNull(valueEmpty);
         assertEquals(BigInteger.ZERO, valueEmpty.getTotal().asWei());
+
+        EthSupply value2 = EthSupply.builder()
+                .withBurntFees(Wei.ofWei(1))
+                .withEth2Staking(Wei.ofWei(1))
+                .withEthSupply(Wei.ofWei(1))
+                .withWithdrawnTotal(Wei.ofWei(1))
+                .build();
+        assertEquals(value, value2);
+        assertEquals(value.hashCode(), value2.hashCode());
+        assertEquals(value.toString(), value2.toString());
     }
 
     @Test
@@ -368,4 +390,13 @@ void blockProxyBuilder() {
         assertNotNull(value);
         assertEquals(BigInteger.valueOf(1), value.getGasUsed().asWei());
     }
+
+    @Test
+    void gasEstimate() {
+        GasEstimate gas1 = new GasEstimate(1);
+        GasEstimate gas2 = new GasEstimate(1);
+        assertEquals(gas1, gas2);
+        assertEquals(gas1.hashCode(), gas2.hashCode());
+        assertEquals(gas1.toString(), gas2.toString());
+    }
 }

From 2d666bcdc67a838483fda2bc81b1f98c9601f355 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 00:57:16 +0300
Subject: [PATCH 43/67] [2.0.0-SNAPSHOT] Log simplified Tests reinforced

---
 .../goodforgod/api/etherscan/model/Log.java   | 12 ++--
 .../etherscan/model/ModelBuilderTests.java    | 72 +++++++++++++++++++
 2 files changed, 77 insertions(+), 7 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index 8e14b16..2808462 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -64,28 +64,26 @@ public Long getTransactionIndex() {
 
     public LocalDateTime getTimeStamp() {
         if (_timeStamp == null && !BasicUtils.isEmpty(timeStamp)) {
-            long formatted = (timeStamp.charAt(0) == '0' && timeStamp.charAt(1) == 'x')
-                    ? BasicUtils.parseHex(timeStamp).longValue()
-                    : Long.parseLong(timeStamp);
+            long formatted = getTimeStampAsSeconds();
             _timeStamp = LocalDateTime.ofEpochSecond(formatted, 0, ZoneOffset.UTC);
         }
         return _timeStamp;
     }
 
     /**
-     * Return the "timeStamp" field of the event record as a long-int representing the milliseconds
+     * Return the "timeStamp" field of the event record as a long-int representing the seconds
      * since the Unix epoch (1970-01-01 00:00:00).
      *
      * @return milliseconds between Unix epoch and `timeStamp`. If field is empty or null, returns null
      */
-    public Long getTimeStampAsMillis() {
+    public Long getTimeStampAsSeconds() {
         if (BasicUtils.isEmpty(timeStamp)) {
             return null;
         }
-        long tsSecs = (timeStamp.charAt(0) == '0' && timeStamp.charAt(1) == 'x')
+
+        return (timeStamp.charAt(0) == '0' && timeStamp.charAt(1) == 'x')
                 ? BasicUtils.parseHex(timeStamp).longValue()
                 : Long.parseLong(timeStamp);
-        return tsSecs * 1000;
     }
 
     public String getData() {
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index 464b379..f895595 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -168,6 +168,31 @@ void txBuilder() {
         assertTrue(value.haveError());
         assertEquals("1", value.getTo());
         assertEquals("1", value.getFrom());
+
+        Tx value2 = Tx.builder()
+                .withBlockHash("1")
+                .withBlockNumber(1L)
+                .withConfirmations(1L)
+                .withContractAddress("1")
+                .withFrom("1")
+                .withTo("1")
+                .withCumulativeGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasPrice(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withHash("1")
+                .withInput("1")
+                .withIsError("1")
+                .withNonce(1L)
+                .withTimeStamp(timestamp)
+                .withValue(BigInteger.ONE)
+                .withTransactionIndex(1)
+                .withTxReceiptStatus("1")
+                .build();
+
+        assertEquals(value, value2);
+        assertEquals(value.hashCode(), value2.hashCode());
+        assertEquals(value.toString(), value2.toString());
     }
 
     @Test
@@ -258,6 +283,32 @@ void txErc1155Builder() {
         assertNotNull(value);
         assertEquals("1", value.getTo());
         assertEquals("1", value.getFrom());
+
+        TxErc1155 value2 = TxErc1155.builder()
+                .withBlockHash("1")
+                .withBlockNumber(1L)
+                .withConfirmations(1L)
+                .withContractAddress("1")
+                .withFrom("1")
+                .withTo("1")
+                .withCumulativeGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasPrice(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withHash("1")
+                .withInput("1")
+                .withTokenName("1")
+                .withTokenSymbol("1")
+                .withTokenDecimal("1")
+                .withTokenID("1")
+                .withNonce(1L)
+                .withTimeStamp(timestamp)
+                .withTransactionIndex(1)
+                .build();
+
+        assertEquals(value, value2);
+        assertEquals(value.hashCode(), value2.hashCode());
+        assertEquals(value.toString(), value2.toString());
     }
 
     @Test
@@ -283,6 +334,27 @@ void txInternalBuilder() {
         assertNotNull(value);
         assertEquals("1", value.getTo());
         assertEquals("1", value.getFrom());
+
+        TxInternal value2 = TxInternal.builder()
+                .withBlockNumber(1L)
+                .withContractAddress("1")
+                .withFrom("1")
+                .withTo("1")
+                .withValue(BigInteger.ONE)
+                .withGas(Wei.ofWei(BigInteger.ONE))
+                .withGasUsed(Wei.ofWei(BigInteger.ONE))
+                .withHash("1")
+                .withInput("1")
+                .withTimeStamp(timestamp)
+                .withErrCode("1")
+                .withIsError(1)
+                .withTraceId("1")
+                .withType("1")
+                .build();
+
+        assertEquals(value, value2);
+        assertEquals(value.hashCode(), value2.hashCode());
+        assertEquals(value.toString(), value2.toString());
     }
 
     @Test

From f09f38a1403a9849ddbb1628a8de61b52620618a Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 01:01:44 +0300
Subject: [PATCH 44/67] [2.0.0] Release prepared

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index e809e6c..821da06 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,6 @@
 groupId=com.github.goodforgod
 artifactId=java-etherscan-api
-artifactVersion=2.0.0-SNAPSHOT
+artifactVersion=2.0.0
 
 
 ##### GRADLE #####

From d1ec9e52ccb84be8bc42805dba075549c9b158d6 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 01:04:11 +0300
Subject: [PATCH 45/67] [2.0.0] Release prepared

---
 README.md | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index 4cff68d..dc939bf 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,6 @@
 [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=coverage)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
 [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
 [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=ncloc)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
-[![](https://jitpack.io/v/GoodforGod/java-etherscan-api.svg)](https://jitpack.io/#GoodforGod/java-etherscan-api)
 
 [Etherscan.io](https://etherscan.io/apis) Java API implementation.
 
@@ -15,7 +14,7 @@ Library supports all available EtherScan *API* calls for all available *Ethereum
 
 **Gradle**
 ```groovy
-implementation "com.github.goodforgod:java-etherscan-api:2.0.0-SNAPSHOT"
+implementation "com.github.goodforgod:java-etherscan-api:2.0.0"
 ```
 
 **Maven**
@@ -23,7 +22,7 @@ implementation "com.github.goodforgod:java-etherscan-api:2.0.0-SNAPSHOT"
 <dependency>
     <groupId>com.github.goodforgod</groupId>
     <artifactId>java-etherscan-api</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.0</version>
 </dependency>
 ```
 
@@ -41,9 +40,9 @@ implementation "com.github.goodforgod:java-etherscan-api:2.0.0-SNAPSHOT"
     - [Token](#token-api)
 - [Version History](#version-history)
 
-## Mainnet and Testnets
+## MainNet and TestNets
 
-API support Ethereum [default networks](https://docs.etherscan.io/getting-started/endpoint-urls):
+API support all Ethereum [default networks](https://docs.etherscan.io/getting-started/endpoint-urls):
 - [Mainnet](https://api.etherscan.io/)
 - [Goerli](https://api-goerli.etherscan.io/)
 - [Sepolia](https://api-sepolia.etherscan.io/)
@@ -121,8 +120,8 @@ Abi abi = api.contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413
 **Get event logs for single topic**
 ```java
 EtherScanAPI api = EtherScanAPI.build();
-LogQuery query = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
-           .topic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
+LogQuery query = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
+           .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
            .build();
 List<Log> logs = api.logs().logs(query);
 ```
@@ -163,7 +162,7 @@ Optional<BlockProxy> block = api.proxy().block(15215);
 **Statistic about last price**
 ```java
 EtherScanAPI api = EtherScanAPI.build();
-Price price = api.stats().lastPrice();
+Price price = api.stats().priceLast();
 ```
 
 ### Transaction API

From b05bd8adf89d56857d0769227b28f3584d8051ca Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 20:49:06 +0300
Subject: [PATCH 46/67] [2.0.0] Tx refactored and simplified and common parts
 moved to BlockTx Comparable for multiple models added GasOracle simplified
 and reinforced Price reinforced GasEstimate.java removed as useless

---
 .../api/etherscan/GasTrackerAPI.java          |  8 +-
 .../api/etherscan/GasTrackerAPIProvider.java  |  6 +-
 .../api/etherscan/model/BaseTx.java           | 17 +---
 .../goodforgod/api/etherscan/model/Block.java |  9 +-
 .../api/etherscan/model/BlockTx.java          | 79 +++++++++++++++++
 .../api/etherscan/model/GasEstimate.java      | 45 ----------
 .../api/etherscan/model/GasOracle.java        | 40 +++++----
 .../goodforgod/api/etherscan/model/Log.java   |  6 --
 .../goodforgod/api/etherscan/model/Price.java | 19 ++--
 .../api/etherscan/model/Status.java           | 14 +--
 .../api/etherscan/model/TokenBalance.java     |  9 +-
 .../io/goodforgod/api/etherscan/model/Tx.java | 75 ++++------------
 .../api/etherscan/model/TxErc1155.java        | 54 ++++--------
 .../api/etherscan/model/TxErc20.java          | 53 ++++-------
 .../api/etherscan/model/TxErc721.java         | 54 ++++--------
 .../api/etherscan/model/TxInternal.java       | 17 +++-
 .../goodforgod/api/etherscan/model/Wei.java   | 87 +++++++++++++++----
 .../api/etherscan/model/proxy/BlockProxy.java | 42 +++------
 .../etherscan/model/proxy/ReceiptProxy.java   | 36 ++------
 .../api/etherscan/model/proxy/TxProxy.java    | 46 ++++------
 .../gastracker/GasTrackerApiTests.java        |  5 +-
 .../etherscan/model/ModelBuilderTests.java    | 60 ++++++++++---
 .../proxy/ProxyTxReceiptApiTests.java         |  2 +-
 23 files changed, 368 insertions(+), 415 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java

diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
index 355d62a..6fce763 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPI.java
@@ -1,9 +1,9 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
-import io.goodforgod.api.etherscan.model.GasEstimate;
 import io.goodforgod.api.etherscan.model.GasOracle;
 import io.goodforgod.api.etherscan.model.Wei;
+import java.time.Duration;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -16,13 +16,13 @@
 public interface GasTrackerAPI {
 
     /**
-     * Returns the estimated time, in seconds, for a transaction to be confirmed on the blockchain.
+     * Returns the estimated time for a transaction to be confirmed on the blockchain.
      *
-     * @return fast, suggested gas price
+     * @return estimated time
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    GasEstimate estimate(@NotNull Wei wei) throws EtherScanException;
+    Duration estimate(@NotNull Wei wei) throws EtherScanException;
 
     /**
      * Returns the current Safe, Proposed and Fast gas prices.
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
index 0b559d8..cbe0a75 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
@@ -4,11 +4,11 @@
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
-import io.goodforgod.api.etherscan.model.GasEstimate;
 import io.goodforgod.api.etherscan.model.GasOracle;
 import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.model.response.GasEstimateResponseTO;
 import io.goodforgod.api.etherscan.model.response.GasOracleResponseTO;
+import java.time.Duration;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -33,13 +33,13 @@ final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI
     }
 
     @Override
-    public @NotNull GasEstimate estimate(@NotNull Wei wei) throws EtherScanException {
+    public @NotNull Duration estimate(@NotNull Wei wei) throws EtherScanException {
         final String urlParams = ACT_GAS_ESTIMATE_PARAM + GASPRICE_PARAM + wei.asWei().toString();
         final GasEstimateResponseTO response = getRequest(urlParams, GasEstimateResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
-        return new GasEstimate(Long.parseLong(response.getResult()));
+        return Duration.ofSeconds(Long.parseLong(response.getResult()));
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
index 64a9627..8de679a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
@@ -6,12 +6,13 @@
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * @author GoodforGod
  * @since 28.10.2018
  */
-abstract class BaseTx {
+abstract class BaseTx implements Comparable<BaseTx> {
 
     long blockNumber;
     String timeStamp;
@@ -84,17 +85,7 @@ public int hashCode() {
     }
 
     @Override
-    public String toString() {
-        return "BaseTx{" +
-                "blockNumber=" + blockNumber +
-                ", timeStamp='" + timeStamp + '\'' +
-                ", hash='" + hash + '\'' +
-                ", from='" + from + '\'' +
-                ", to='" + to + '\'' +
-                ", contractAddress='" + contractAddress + '\'' +
-                ", input='" + input + '\'' +
-                ", gas=" + gas +
-                ", gasUsed=" + gasUsed +
-                '}';
+    public int compareTo(@NotNull BaseTx o) {
+        return Long.compare(blockNumber, o.blockNumber);
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Block.java b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
index 95bfbcb..9fe4e02 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Block.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
@@ -6,12 +6,13 @@
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class Block {
+public class Block implements Comparable<Block> {
 
     long blockNumber;
     BigInteger blockReward;
@@ -58,10 +59,14 @@ public String toString() {
                 "blockNumber=" + blockNumber +
                 ", blockReward=" + blockReward +
                 ", timeStamp='" + timeStamp + '\'' +
-                ", _timeStamp=" + _timeStamp +
                 '}';
     }
 
+    @Override
+    public int compareTo(@NotNull Block o) {
+        return Long.compare(blockNumber, o.blockNumber);
+    }
+
     public static BlockBuilder builder() {
         return new BlockBuilder();
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java
new file mode 100644
index 0000000..f3c4d67
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java
@@ -0,0 +1,79 @@
+package io.goodforgod.api.etherscan.model;
+
+import java.math.BigInteger;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Anton Kurako (GoodforGod)
+ * @since 15.05.2023
+ */
+abstract class BlockTx extends BaseTx {
+
+    long nonce;
+    String blockHash;
+    long transactionIndex;
+    long confirmations;
+    BigInteger gasPrice;
+    BigInteger cumulativeGasUsed;
+
+    public long getNonce() {
+        return nonce;
+    }
+
+    public String getBlockHash() {
+        return blockHash;
+    }
+
+    public long getTransactionIndex() {
+        return transactionIndex;
+    }
+
+    public Wei getGasPrice() {
+        return Wei.ofWei(gasPrice);
+    }
+
+    public Wei getGasUsedCumulative() {
+        return Wei.ofWei(cumulativeGasUsed);
+    }
+
+    public long getConfirmations() {
+        return confirmations;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (!(o instanceof BlockTx))
+            return false;
+        if (!super.equals(o))
+            return false;
+        BlockTx blockTx = (BlockTx) o;
+        return nonce == blockTx.nonce && transactionIndex == blockTx.transactionIndex
+                && Objects.equals(blockHash, blockTx.blockHash);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), nonce, blockHash, transactionIndex);
+    }
+
+    @Override
+    public int compareTo(@NotNull BaseTx o) {
+        final int superCompare = super.compareTo(o);
+        if (superCompare == 0) {
+            if (o instanceof Tx) {
+                return Long.compare(transactionIndex, ((Tx) o).getTransactionIndex());
+            } else if (o instanceof TxErc20) {
+                return Long.compare(transactionIndex, ((TxErc20) o).getTransactionIndex());
+            } else if (o instanceof TxErc721) {
+                return Long.compare(transactionIndex, ((TxErc721) o).getTransactionIndex());
+            } else if (o instanceof TxErc1155) {
+                return Long.compare(transactionIndex, ((TxErc1155) o).getTransactionIndex());
+            }
+        }
+
+        return superCompare;
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java b/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
deleted file mode 100644
index 198e53c..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasEstimate.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package io.goodforgod.api.etherscan.model;
-
-import java.time.Duration;
-import java.util.Objects;
-
-/**
- * @author GoodforGod
- * @since 14.05.2023
- */
-public class GasEstimate {
-
-    private final Duration duration;
-
-    public GasEstimate(long durationInSeconds) {
-        this.duration = Duration.ofSeconds(durationInSeconds);
-    }
-
-    public GasEstimate(Duration duration) {
-        this.duration = duration;
-    }
-
-    public Duration getDuration() {
-        return duration;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (!(o instanceof GasEstimate))
-            return false;
-        GasEstimate that = (GasEstimate) o;
-        return Objects.equals(duration, that.duration);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(duration);
-    }
-
-    @Override
-    public String toString() {
-        return duration.toString();
-    }
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
index d273357..6fe1231 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
@@ -14,10 +14,10 @@
 public class GasOracle {
 
     private Long LastBlock;
-    private Integer SafeGasPrice;
-    private Integer ProposeGasPrice;
-    private Integer FastGasPrice;
-    private Double suggestBaseFee;
+    private BigInteger SafeGasPrice;
+    private BigInteger ProposeGasPrice;
+    private BigInteger FastGasPrice;
+    private BigDecimal suggestBaseFee;
     private String gasUsedRatio;
 
     protected GasOracle() {}
@@ -27,18 +27,18 @@ public Long getLastBlock() {
     }
 
     public Wei getSafeGasPriceInWei() {
-        return Wei.ofWei(BigInteger.valueOf(SafeGasPrice).multiply(BigInteger.TEN.pow(9)));
+        return Wei.ofGwei(SafeGasPrice);
     }
 
     public Wei getProposeGasPriceInWei() {
-        return Wei.ofWei(BigInteger.valueOf(ProposeGasPrice).multiply(BigInteger.TEN.pow(9)));
+        return Wei.ofGwei(ProposeGasPrice);
     }
 
     public Wei getFastGasPriceInWei() {
-        return Wei.ofWei(BigInteger.valueOf(FastGasPrice).multiply(BigInteger.TEN.pow(9)));
+        return Wei.ofGwei(FastGasPrice);
     }
 
-    public Double getSuggestBaseFee() {
+    public BigDecimal getSuggestBaseFee() {
         return suggestBaseFee;
     }
 
@@ -52,12 +52,14 @@ public List<BigDecimal> getGasUsedRatio() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof GasOracle))
             return false;
         GasOracle gasOracle = (GasOracle) o;
-        return LastBlock.equals(gasOracle.LastBlock) && SafeGasPrice.equals(gasOracle.SafeGasPrice)
-                && ProposeGasPrice.equals(gasOracle.ProposeGasPrice) && FastGasPrice.equals(gasOracle.FastGasPrice)
-                && suggestBaseFee.equals(gasOracle.suggestBaseFee) && gasUsedRatio.equals(gasOracle.gasUsedRatio);
+        return Objects.equals(LastBlock, gasOracle.LastBlock) && Objects.equals(SafeGasPrice, gasOracle.SafeGasPrice)
+                && Objects.equals(ProposeGasPrice, gasOracle.ProposeGasPrice)
+                && Objects.equals(FastGasPrice, gasOracle.FastGasPrice)
+                && Objects.equals(suggestBaseFee, gasOracle.suggestBaseFee)
+                && Objects.equals(gasUsedRatio, gasOracle.gasUsedRatio);
     }
 
     @Override
@@ -73,7 +75,7 @@ public String toString() {
                 ", ProposeGasPrice=" + ProposeGasPrice +
                 ", FastGasPrice=" + FastGasPrice +
                 ", suggestBaseFee=" + suggestBaseFee +
-                ", gasUsedRatio='" + gasUsedRatio + '\'' +
+                ", gasUsedRatio=" + gasUsedRatio +
                 '}';
     }
 
@@ -87,7 +89,7 @@ public static final class GasOracleBuilder {
         private Wei safeGasPrice;
         private Wei proposeGasPrice;
         private Wei fastGasPrice;
-        private Double suggestBaseFee;
+        private BigDecimal suggestBaseFee;
         private List<BigDecimal> gasUsedRatio;
 
         private GasOracleBuilder() {}
@@ -112,7 +114,7 @@ public GasOracleBuilder withFastGasPrice(Wei fastGasPrice) {
             return this;
         }
 
-        public GasOracleBuilder withSuggestBaseFee(Double suggestBaseFee) {
+        public GasOracleBuilder withSuggestBaseFee(BigDecimal suggestBaseFee) {
             this.suggestBaseFee = suggestBaseFee;
             return this;
         }
@@ -127,18 +129,18 @@ public GasOracle build() {
             gasOracle.LastBlock = this.lastBlock;
             gasOracle.suggestBaseFee = this.suggestBaseFee;
             if (this.proposeGasPrice != null) {
-                gasOracle.ProposeGasPrice = this.proposeGasPrice.asGwei().intValue();
+                gasOracle.ProposeGasPrice = this.proposeGasPrice.asGwei().toBigInteger();
             }
             if (this.safeGasPrice != null) {
-                gasOracle.SafeGasPrice = this.safeGasPrice.asGwei().intValue();
+                gasOracle.SafeGasPrice = this.safeGasPrice.asGwei().toBigInteger();
             }
             if (this.fastGasPrice != null) {
-                gasOracle.FastGasPrice = this.fastGasPrice.asGwei().intValue();
+                gasOracle.FastGasPrice = this.fastGasPrice.asGwei().toBigInteger();
             }
             if (this.gasUsedRatio != null) {
                 gasOracle.gasUsedRatio = this.gasUsedRatio.stream()
                         .map(BigDecimal::toString)
-                        .collect(Collectors.joining(", "));
+                        .collect(Collectors.joining(","));
             }
             return gasOracle;
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index 2808462..da6c295 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -139,21 +139,15 @@ public int hashCode() {
     public String toString() {
         return "Log{" +
                 "blockNumber='" + blockNumber + '\'' +
-                ", _blockNumber=" + _blockNumber +
                 ", address='" + address + '\'' +
                 ", transactionHash='" + transactionHash + '\'' +
                 ", transactionIndex='" + transactionIndex + '\'' +
-                ", _transactionIndex=" + _transactionIndex +
                 ", timeStamp='" + timeStamp + '\'' +
-                ", _timeStamp=" + _timeStamp +
                 ", data='" + data + '\'' +
                 ", gasPrice='" + gasPrice + '\'' +
-                ", _gasPrice=" + _gasPrice +
                 ", gasUsed='" + gasUsed + '\'' +
-                ", _gasUsed=" + _gasUsed +
                 ", topics=" + topics +
                 ", logIndex='" + logIndex + '\'' +
-                ", _logIndex=" + _logIndex +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
index 4ef4491..d2a8091 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan.model;
 
 import com.google.gson.annotations.Expose;
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.Objects;
@@ -11,8 +12,8 @@
  */
 public class Price {
 
-    private double ethusd;
-    private double ethbtc;
+    private BigDecimal ethusd;
+    private BigDecimal ethbtc;
     private String ethusd_timestamp;
     private String ethbtc_timestamp;
     @Expose(deserialize = false, serialize = false)
@@ -22,11 +23,11 @@ public class Price {
 
     protected Price() {}
 
-    public double inUsd() {
+    public BigDecimal inUsd() {
         return ethusd;
     }
 
-    public double inBtc() {
+    public BigDecimal inBtc() {
         return ethbtc;
     }
 
@@ -51,7 +52,7 @@ public boolean equals(Object o) {
         if (!(o instanceof Price))
             return false;
         Price price = (Price) o;
-        return Double.compare(price.ethusd, ethusd) == 0 && Double.compare(price.ethbtc, ethbtc) == 0
+        return Objects.equals(ethusd, price.ethusd) && Objects.equals(ethbtc, price.ethbtc)
                 && Objects.equals(ethusd_timestamp, price.ethusd_timestamp)
                 && Objects.equals(ethbtc_timestamp, price.ethbtc_timestamp);
     }
@@ -77,19 +78,19 @@ public static PriceBuilder builder() {
 
     public static final class PriceBuilder {
 
-        private double ethusd;
-        private double ethbtc;
+        private BigDecimal ethusd;
+        private BigDecimal ethbtc;
         private LocalDateTime ethusdTimestamp;
         private LocalDateTime ethbtcTimestamp;
 
         private PriceBuilder() {}
 
-        public PriceBuilder withEthUsd(double ethusd) {
+        public PriceBuilder withEthUsd(BigDecimal ethusd) {
             this.ethusd = ethusd;
             return this;
         }
 
-        public PriceBuilder withEthBtc(double ethbtc) {
+        public PriceBuilder withEthBtc(BigDecimal ethbtc) {
             this.ethbtc = ethbtc;
             return this;
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Status.java b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
index eaf9b8a..052c187 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Status.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
@@ -30,23 +30,15 @@ public String getErrDescription() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof Status))
             return false;
-
         Status status = (Status) o;
-
-        if (isError != status.isError)
-            return false;
-        return Objects.equals(errDescription, status.errDescription);
+        return isError == status.isError && Objects.equals(errDescription, status.errDescription);
     }
 
     @Override
     public int hashCode() {
-        int result = isError;
-        result = 31 * result + (errDescription != null
-                ? errDescription.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(isError, errDescription);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
index 0c1a5b5..bb40ee2 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
@@ -23,22 +23,17 @@ public String getContract() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof TokenBalance))
             return false;
         if (!super.equals(o))
             return false;
-
         TokenBalance that = (TokenBalance) o;
         return Objects.equals(tokenContract, that.tokenContract);
     }
 
     @Override
     public int hashCode() {
-        int result = super.hashCode();
-        result = 31 * result + (tokenContract != null
-                ? tokenContract.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(super.hashCode(), tokenContract);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 819252e..7ef0e22 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -4,21 +4,14 @@
 import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
-import java.util.Objects;
 
 /**
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class Tx extends BaseTx {
+public class Tx extends BlockTx {
 
     private BigInteger value;
-    private long nonce;
-    private String blockHash;
-    private int transactionIndex;
-    private BigInteger gasPrice;
-    private BigInteger cumulativeGasUsed;
-    private long confirmations;
     private String isError;
     private String txreceipt_status;
 
@@ -29,22 +22,6 @@ public BigInteger getValue() {
         return value;
     }
 
-    public long getNonce() {
-        return nonce;
-    }
-
-    public String getBlockHash() {
-        return blockHash;
-    }
-
-    public int getTransactionIndex() {
-        return transactionIndex;
-    }
-
-    public Wei getGasPrice() {
-        return Wei.ofWei(gasPrice);
-    }
-
     public boolean haveError() {
         return !BasicUtils.isEmpty(isError) && !isError.equals("0");
     }
@@ -52,50 +29,30 @@ public boolean haveError() {
     public String getTxReceiptStatus() {
         return txreceipt_status;
     }
-
-    public Wei getGasUsedCumulative() {
-        return Wei.ofWei(cumulativeGasUsed);
-    }
-
-    public long getConfirmations() {
-        return confirmations;
-    }
     // </editor-fold>
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (!(o instanceof Tx))
-            return false;
-        if (!super.equals(o))
-            return false;
-        Tx tx = (Tx) o;
-        return nonce == tx.nonce && transactionIndex == tx.transactionIndex && confirmations == tx.confirmations
-                && Objects.equals(value, tx.value) && Objects.equals(blockHash, tx.blockHash)
-                && Objects.equals(gasPrice, tx.gasPrice) && Objects.equals(cumulativeGasUsed, tx.cumulativeGasUsed)
-                && Objects.equals(isError, tx.isError) && Objects.equals(txreceipt_status, tx.txreceipt_status);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), value, nonce, blockHash, transactionIndex, gasPrice, cumulativeGasUsed,
-                confirmations, isError, txreceipt_status);
-    }
-
     @Override
     public String toString() {
         return "Tx{" +
-                "nonce=" + nonce +
-                ", value='" + value + '\'' +
+                "value=" + value +
+                ", isError='" + isError + '\'' +
+                ", txreceipt_status='" + txreceipt_status + '\'' +
+                ", nonce=" + nonce +
                 ", blockHash='" + blockHash + '\'' +
                 ", transactionIndex=" + transactionIndex +
+                ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
-                ", confirmations=" + confirmations +
-                ", isError='" + isError + '\'' +
-                ", txreceipt_status='" + txreceipt_status + '\'' +
-                "} " + super.toString();
+                ", blockNumber=" + blockNumber +
+                ", timeStamp='" + timeStamp + '\'' +
+                ", hash='" + hash + '\'' +
+                ", from='" + from + '\'' +
+                ", to='" + to + '\'' +
+                ", contractAddress='" + contractAddress + '\'' +
+                ", input='" + input + '\'' +
+                ", gas=" + gas +
+                ", gasUsed=" + gasUsed +
+                '}';
     }
 
     public static TxBuilder builder() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
index 7be8aff..16d4457 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -1,6 +1,5 @@
 package io.goodforgod.api.etherscan.model;
 
-import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.Objects;
@@ -9,30 +8,16 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class TxErc1155 extends BaseTx {
+public class TxErc1155 extends BlockTx {
 
-    private long nonce;
-    private String blockHash;
     private String tokenID;
     private String tokenName;
     private String tokenSymbol;
     private String tokenValue;
-    private int transactionIndex;
-    private BigInteger gasPrice;
-    private BigInteger cumulativeGasUsed;
-    private long confirmations;
 
     protected TxErc1155() {}
 
     // <editor-fold desc="Getters">
-    public long getNonce() {
-        return nonce;
-    }
-
-    public String getBlockHash() {
-        return blockHash;
-    }
-
     public String getTokenID() {
         return tokenID;
     }
@@ -48,22 +33,6 @@ public String getTokenSymbol() {
     public String getTokenValue() {
         return tokenValue;
     }
-
-    public int getTransactionIndex() {
-        return transactionIndex;
-    }
-
-    public Wei getGasPrice() {
-        return Wei.ofWei(gasPrice);
-    }
-
-    public Wei getGasUsedCumulative() {
-        return Wei.ofWei(cumulativeGasUsed);
-    }
-
-    public long getConfirmations() {
-        return confirmations;
-    }
     // </editor-fold>
 
     @Override
@@ -86,18 +55,27 @@ public int hashCode() {
 
     @Override
     public String toString() {
-        return "TxERC721{" +
-                "nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
-                ", tokenID='" + tokenID + '\'' +
+        return "TxErc1155{" +
+                "tokenID='" + tokenID + '\'' +
                 ", tokenName='" + tokenName + '\'' +
                 ", tokenSymbol='" + tokenSymbol + '\'' +
                 ", tokenValue='" + tokenValue + '\'' +
+                ", nonce=" + nonce +
+                ", blockHash='" + blockHash + '\'' +
                 ", transactionIndex=" + transactionIndex +
+                ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
-                ", confirmations=" + confirmations +
-                "} " + super.toString();
+                ", blockNumber=" + blockNumber +
+                ", timeStamp='" + timeStamp + '\'' +
+                ", hash='" + hash + '\'' +
+                ", from='" + from + '\'' +
+                ", to='" + to + '\'' +
+                ", contractAddress='" + contractAddress + '\'' +
+                ", input='" + input + '\'' +
+                ", gas=" + gas +
+                ", gasUsed=" + gasUsed +
+                '}';
     }
 
     public static TxErc1155Builder builder() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index 751044c..3dc22fd 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -9,30 +9,16 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class TxErc20 extends BaseTx {
+public class TxErc20 extends BlockTx {
 
     private BigInteger value;
-    private long nonce;
-    private String blockHash;
     private String tokenName;
     private String tokenSymbol;
     private String tokenDecimal;
-    private int transactionIndex;
-    private BigInteger gasPrice;
-    private BigInteger cumulativeGasUsed;
-    private long confirmations;
 
     protected TxErc20() {}
 
     // <editor-fold desc="Getters">
-    public long getNonce() {
-        return nonce;
-    }
-
-    public String getBlockHash() {
-        return blockHash;
-    }
-
     public BigInteger getValue() {
         return value;
     }
@@ -48,22 +34,6 @@ public String getTokenSymbol() {
     public String getTokenDecimal() {
         return tokenDecimal;
     }
-
-    public int getTransactionIndex() {
-        return transactionIndex;
-    }
-
-    public Wei getGasPrice() {
-        return Wei.ofWei(gasPrice);
-    }
-
-    public Wei getGasUsedCumulative() {
-        return Wei.ofWei(cumulativeGasUsed);
-    }
-
-    public long getConfirmations() {
-        return confirmations;
-    }
     // </editor-fold>
 
     @Override
@@ -86,18 +56,27 @@ public int hashCode() {
 
     @Override
     public String toString() {
-        return "TxERC20{" +
-                "nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
-                ", value='" + value + '\'' +
+        return "TxErc20{" +
+                "value=" + value +
                 ", tokenName='" + tokenName + '\'' +
                 ", tokenSymbol='" + tokenSymbol + '\'' +
                 ", tokenDecimal='" + tokenDecimal + '\'' +
+                ", nonce=" + nonce +
+                ", blockHash='" + blockHash + '\'' +
                 ", transactionIndex=" + transactionIndex +
+                ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
-                ", confirmations=" + confirmations +
-                "} " + super.toString();
+                ", blockNumber=" + blockNumber +
+                ", timeStamp='" + timeStamp + '\'' +
+                ", hash='" + hash + '\'' +
+                ", from='" + from + '\'' +
+                ", to='" + to + '\'' +
+                ", contractAddress='" + contractAddress + '\'' +
+                ", input='" + input + '\'' +
+                ", gas=" + gas +
+                ", gasUsed=" + gasUsed +
+                '}';
     }
 
     public static TxERC20Builder builder() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 7b59393..2180019 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -1,6 +1,5 @@
 package io.goodforgod.api.etherscan.model;
 
-import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.Objects;
@@ -9,30 +8,16 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-public class TxErc721 extends BaseTx {
+public class TxErc721 extends BlockTx {
 
-    private long nonce;
-    private String blockHash;
     private String tokenID;
     private String tokenName;
     private String tokenSymbol;
     private String tokenDecimal;
-    private int transactionIndex;
-    private BigInteger gasPrice;
-    private BigInteger cumulativeGasUsed;
-    private long confirmations;
 
     protected TxErc721() {}
 
     // <editor-fold desc="Getters">
-    public long getNonce() {
-        return nonce;
-    }
-
-    public String getBlockHash() {
-        return blockHash;
-    }
-
     public String getTokenID() {
         return tokenID;
     }
@@ -48,22 +33,6 @@ public String getTokenSymbol() {
     public String getTokenDecimal() {
         return tokenDecimal;
     }
-
-    public int getTransactionIndex() {
-        return transactionIndex;
-    }
-
-    public Wei getGasPrice() {
-        return Wei.ofWei(gasPrice);
-    }
-
-    public Wei getGasUsedCumulative() {
-        return Wei.ofWei(cumulativeGasUsed);
-    }
-
-    public long getConfirmations() {
-        return confirmations;
-    }
     // </editor-fold>
 
     @Override
@@ -86,18 +55,27 @@ public int hashCode() {
 
     @Override
     public String toString() {
-        return "TxERC721{" +
-                "nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
-                ", tokenID='" + tokenID + '\'' +
+        return "TxErc721{" +
+                "tokenID='" + tokenID + '\'' +
                 ", tokenName='" + tokenName + '\'' +
                 ", tokenSymbol='" + tokenSymbol + '\'' +
                 ", tokenDecimal='" + tokenDecimal + '\'' +
+                ", nonce=" + nonce +
+                ", blockHash='" + blockHash + '\'' +
                 ", transactionIndex=" + transactionIndex +
+                ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
-                ", confirmations=" + confirmations +
-                "} " + super.toString();
+                ", blockNumber=" + blockNumber +
+                ", timeStamp='" + timeStamp + '\'' +
+                ", hash='" + hash + '\'' +
+                ", from='" + from + '\'' +
+                ", to='" + to + '\'' +
+                ", contractAddress='" + contractAddress + '\'' +
+                ", input='" + input + '\'' +
+                ", gas=" + gas +
+                ", gasUsed=" + gasUsed +
+                '}';
     }
 
     public static TxERC721Builder builder() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index dd74e99..a61cf83 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -68,12 +68,21 @@ public int hashCode() {
     @Override
     public String toString() {
         return "TxInternal{" +
-                "type='" + type + '\'' +
-                ", traceId=" + traceId +
-                ", value=" + value +
+                "value=" + value +
+                ", type='" + type + '\'' +
+                ", traceId='" + traceId + '\'' +
                 ", isError=" + isError +
                 ", errCode='" + errCode + '\'' +
-                "} " + super.toString();
+                ", blockNumber=" + blockNumber +
+                ", timeStamp='" + timeStamp + '\'' +
+                ", hash='" + hash + '\'' +
+                ", from='" + from + '\'' +
+                ", to='" + to + '\'' +
+                ", contractAddress='" + contractAddress + '\'' +
+                ", input='" + input + '\'' +
+                ", gas=" + gas +
+                ", gasUsed=" + gasUsed +
+                '}';
     }
 
     public static TxInternalBuilder builder() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
index 038fd4b..3180478 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Wei.java
@@ -4,12 +4,18 @@
 import java.math.BigInteger;
 import java.math.RoundingMode;
 import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * @author GoodforGod
  * @since 30.10.2018
  */
-public class Wei {
+public class Wei implements Comparable<Wei> {
+
+    private static final BigDecimal KWEI_POW = BigDecimal.ONE.pow(3);
+    private static final BigDecimal MWEI_POW = BigDecimal.ONE.pow(6);
+    private static final BigDecimal GWEI_POW = BigDecimal.ONE.pow(9);
+    private static final BigDecimal WEI_POW = BigDecimal.ONE.pow(18);
 
     private final BigInteger result;
 
@@ -18,54 +24,100 @@ private Wei(BigInteger value) {
     }
 
     public static Wei ofWei(int value) {
-        return new Wei(BigInteger.valueOf(value));
+        return ofWei(BigInteger.valueOf(value));
     }
 
     public static Wei ofWei(long value) {
-        return new Wei(BigInteger.valueOf(value));
+        return ofWei(BigInteger.valueOf(value));
     }
 
     public static Wei ofWei(BigInteger value) {
         return new Wei(value);
     }
 
+    public static Wei ofKwei(int value) {
+        return ofKwei(BigInteger.valueOf(value));
+    }
+
+    public static Wei ofKwei(long value) {
+        return ofKwei(BigInteger.valueOf(value));
+    }
+
+    public static Wei ofKwei(BigDecimal value) {
+        return new Wei(value.multiply(KWEI_POW).toBigInteger());
+    }
+
+    public static Wei ofKwei(BigInteger value) {
+        return new Wei(value.multiply(KWEI_POW.toBigInteger()));
+    }
+
+    public static Wei ofMwei(int value) {
+        return ofMwei(BigInteger.valueOf(value));
+    }
+
+    public static Wei ofMwei(long value) {
+        return ofMwei(BigInteger.valueOf(value));
+    }
+
+    public static Wei ofMwei(BigDecimal value) {
+        return new Wei(value.multiply(MWEI_POW).toBigInteger());
+    }
+
+    public static Wei ofMwei(BigInteger value) {
+        return new Wei(value.multiply(MWEI_POW.toBigInteger()));
+    }
+
+    public static Wei ofGwei(int value) {
+        return ofGwei(BigInteger.valueOf(value));
+    }
+
+    public static Wei ofGwei(long value) {
+        return ofGwei(BigInteger.valueOf(value));
+    }
+
+    public static Wei ofGwei(BigDecimal value) {
+        return new Wei(value.multiply(GWEI_POW).toBigInteger());
+    }
+
+    public static Wei ofGwei(BigInteger value) {
+        return new Wei(value.multiply(GWEI_POW.toBigInteger()));
+    }
+
     public static Wei ofEther(int value) {
-        return new Wei(BigInteger.valueOf(value).multiply(BigInteger.valueOf(1_000_000_000_000_000L)));
+        return ofEther(BigInteger.valueOf(value));
     }
 
     public static Wei ofEther(long value) {
-        return new Wei(BigInteger.valueOf(value).multiply(BigInteger.valueOf(1_000_000_000_000_000L)));
+        return ofEther(BigInteger.valueOf(value));
     }
 
-    public static Wei ofEther(BigInteger value) {
-        return new Wei(value.multiply(BigInteger.valueOf(1_000_000_000_000_000L)));
+    public static Wei ofEther(BigDecimal value) {
+        return new Wei(value.multiply(WEI_POW).toBigInteger());
     }
 
-    public static Wei ofEther(BigDecimal value) {
-        return new Wei(value.multiply(BigDecimal.valueOf(1_000_000_000_000_000L)).toBigInteger());
+    public static Wei ofEther(BigInteger value) {
+        return new Wei(value.multiply(WEI_POW.toBigInteger()));
     }
 
-    // <editor-fold desc="Getters">
     public BigInteger asWei() {
         return result;
     }
 
     public BigDecimal asKwei() {
-        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000), RoundingMode.HALF_UP);
+        return new BigDecimal(result).divide(KWEI_POW, RoundingMode.HALF_UP);
     }
 
     public BigDecimal asMwei() {
-        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000_000), RoundingMode.HALF_UP);
+        return new BigDecimal(result).divide(MWEI_POW, RoundingMode.HALF_UP);
     }
 
     public BigDecimal asGwei() {
-        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000_000_000), RoundingMode.HALF_UP);
+        return new BigDecimal(result).divide(GWEI_POW, RoundingMode.HALF_UP);
     }
 
     public BigDecimal asEther() {
-        return new BigDecimal(result).divide(BigDecimal.valueOf(1_000_000_000_000_000L), RoundingMode.HALF_UP);
+        return new BigDecimal(result).divide(WEI_POW, RoundingMode.HALF_UP);
     }
-    // </editor-fold>
 
     @Override
     public boolean equals(Object o) {
@@ -82,6 +134,11 @@ public int hashCode() {
         return Objects.hash(result);
     }
 
+    @Override
+    public int compareTo(@NotNull Wei o) {
+        return result.compareTo(o.result);
+    }
+
     @Override
     public String toString() {
         return result.toString();
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index c98d5ee..4a2b624 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -6,12 +6,14 @@
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.List;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * @author GoodforGod
  * @since 31.10.2018
  */
-public class BlockProxy {
+public class BlockProxy implements Comparable<BlockProxy> {
 
     private String number;
     @Expose(deserialize = false, serialize = false)
@@ -145,61 +147,36 @@ public List<TxProxy> getTransactions() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof BlockProxy))
             return false;
-
         BlockProxy that = (BlockProxy) o;
-
-        if (number != null
-                ? !number.equals(that.number)
-                : that.number != null)
-            return false;
-        if (hash != null
-                ? !hash.equals(that.hash)
-                : that.hash != null)
-            return false;
-        return parentHash != null
-                ? parentHash.equals(that.parentHash)
-                : that.parentHash == null;
+        return Objects.equals(number, that.number) && Objects.equals(hash, that.hash)
+                && Objects.equals(parentHash, that.parentHash) && Objects.equals(nonce, that.nonce);
     }
 
     @Override
     public int hashCode() {
-        int result = number != null
-                ? number.hashCode()
-                : 0;
-        result = 31 * result + (hash != null
-                ? hash.hashCode()
-                : 0);
-        result = 31 * result + (parentHash != null
-                ? parentHash.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(number, hash, parentHash, nonce);
     }
 
     @Override
     public String toString() {
         return "BlockProxy{" +
                 "number='" + number + '\'' +
-                ", _number=" + _number +
                 ", hash='" + hash + '\'' +
                 ", parentHash='" + parentHash + '\'' +
                 ", stateRoot='" + stateRoot + '\'' +
                 ", size='" + size + '\'' +
-                ", _size=" + _size +
                 ", difficulty='" + difficulty + '\'' +
                 ", totalDifficulty='" + totalDifficulty + '\'' +
                 ", timestamp='" + timestamp + '\'' +
-                ", _timestamp=" + _timestamp +
                 ", miner='" + miner + '\'' +
                 ", nonce='" + nonce + '\'' +
                 ", extraData='" + extraData + '\'' +
                 ", logsBloom='" + logsBloom + '\'' +
                 ", mixHash='" + mixHash + '\'' +
                 ", gasUsed='" + gasUsed + '\'' +
-                ", _gasUsed=" + _gasUsed +
                 ", gasLimit='" + gasLimit + '\'' +
-                ", _gasLimit=" + _gasLimit +
                 ", sha3Uncles='" + sha3Uncles + '\'' +
                 ", uncles=" + uncles +
                 ", receiptsRoot='" + receiptsRoot + '\'' +
@@ -208,6 +185,11 @@ public String toString() {
                 '}';
     }
 
+    @Override
+    public int compareTo(@NotNull BlockProxy o) {
+        return Long.compare(getNumber(), o.getNumber());
+    }
+
     public static BlockProxyBuilder builder() {
         return new BlockProxyBuilder();
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index 2b616c3..e6df01c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -5,6 +5,7 @@
 import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -75,7 +76,7 @@ public Wei getGasUsed() {
         return _gasUsed;
     }
 
-    public Wei getCumulativeGasUsed() {
+    public Wei getGasUsedCumulative() {
         if (_cumulativeGasUsed == null && !BasicUtils.isEmpty(cumulativeGasUsed))
             _cumulativeGasUsed = Wei.ofWei(BasicUtils.parseHex(cumulativeGasUsed));
         return _cumulativeGasUsed;
@@ -98,36 +99,17 @@ public String getLogsBloom() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof ReceiptProxy))
             return false;
-
         ReceiptProxy that = (ReceiptProxy) o;
-
-        if (blockNumber != null
-                ? !blockNumber.equals(that.blockNumber)
-                : that.blockNumber != null)
-            return false;
-        if (transactionHash != null
-                ? !transactionHash.equals(that.transactionHash)
-                : that.transactionHash != null)
-            return false;
-        return transactionIndex != null
-                ? transactionIndex.equals(that.transactionIndex)
-                : that.transactionIndex == null;
+        return Objects.equals(blockNumber, that.blockNumber) && Objects.equals(blockHash, that.blockHash)
+                && Objects.equals(transactionHash, that.transactionHash)
+                && Objects.equals(transactionIndex, that.transactionIndex);
     }
 
     @Override
     public int hashCode() {
-        int result = blockNumber != null
-                ? blockNumber.hashCode()
-                : 0;
-        result = 31 * result + (transactionHash != null
-                ? transactionHash.hashCode()
-                : 0);
-        result = 31 * result + (transactionIndex != null
-                ? transactionIndex.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(blockNumber, blockHash, transactionHash, transactionIndex);
     }
 
     @Override
@@ -137,15 +119,11 @@ public String toString() {
                 ", from='" + from + '\'' +
                 ", to='" + to + '\'' +
                 ", blockNumber='" + blockNumber + '\'' +
-                ", _blockNumber=" + _blockNumber +
                 ", blockHash='" + blockHash + '\'' +
                 ", transactionHash='" + transactionHash + '\'' +
                 ", transactionIndex='" + transactionIndex + '\'' +
-                ", _transactionIndex=" + _transactionIndex +
                 ", gasUsed='" + gasUsed + '\'' +
-                ", _gasUsed=" + _gasUsed +
                 ", cumulativeGasUsed='" + cumulativeGasUsed + '\'' +
-                ", _cumulativeGasUsed=" + _cumulativeGasUsed +
                 ", contractAddress='" + contractAddress + '\'' +
                 ", logs=" + logs +
                 ", logsBloom='" + logsBloom + '\'' +
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index b2b412b..70b4fd7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -3,12 +3,14 @@
 import com.google.gson.annotations.Expose;
 import io.goodforgod.api.etherscan.model.Wei;
 import io.goodforgod.api.etherscan.util.BasicUtils;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * @author GoodforGod
  * @since 31.10.2018
  */
-public class TxProxy {
+public class TxProxy implements Comparable<TxProxy> {
 
     private String to;
     private String hash;
@@ -109,36 +111,17 @@ public Long getBlockNumber() {
     public boolean equals(Object o) {
         if (this == o)
             return true;
-        if (o == null || getClass() != o.getClass())
+        if (!(o instanceof TxProxy))
             return false;
-
         TxProxy txProxy = (TxProxy) o;
-
-        if (hash != null
-                ? !hash.equals(txProxy.hash)
-                : txProxy.hash != null)
-            return false;
-        if (blockHash != null
-                ? !blockHash.equals(txProxy.blockHash)
-                : txProxy.blockHash != null)
-            return false;
-        return blockNumber != null
-                ? blockNumber.equals(txProxy.blockNumber)
-                : txProxy.blockNumber == null;
+        return Objects.equals(hash, txProxy.hash) && Objects.equals(transactionIndex, txProxy.transactionIndex)
+                && Objects.equals(nonce, txProxy.nonce) && Objects.equals(blockHash, txProxy.blockHash)
+                && Objects.equals(blockNumber, txProxy.blockNumber);
     }
 
     @Override
     public int hashCode() {
-        int result = hash != null
-                ? hash.hashCode()
-                : 0;
-        result = 31 * result + (blockHash != null
-                ? blockHash.hashCode()
-                : 0);
-        result = 31 * result + (blockNumber != null
-                ? blockNumber.hashCode()
-                : 0);
-        return result;
+        return Objects.hash(hash, transactionIndex, nonce, blockHash, blockNumber);
     }
 
     @Override
@@ -147,25 +130,28 @@ public String toString() {
                 "to='" + to + '\'' +
                 ", hash='" + hash + '\'' +
                 ", transactionIndex='" + transactionIndex + '\'' +
-                ", _transactionIndex=" + _transactionIndex +
                 ", from='" + from + '\'' +
                 ", v='" + v + '\'' +
                 ", input='" + input + '\'' +
                 ", s='" + s + '\'' +
                 ", r='" + r + '\'' +
                 ", nonce='" + nonce + '\'' +
-                ", _nonce=" + _nonce +
                 ", value='" + value + '\'' +
                 ", gas='" + gas + '\'' +
-                ", _gas=" + _gas +
                 ", gasPrice='" + gasPrice + '\'' +
-                ", _gasPrice=" + _gasPrice +
                 ", blockHash='" + blockHash + '\'' +
                 ", blockNumber='" + blockNumber + '\'' +
-                ", _blockNumber=" + _blockNumber +
                 '}';
     }
 
+    @Override
+    public int compareTo(@NotNull TxProxy o) {
+        final int firstCompare = Long.compare(getBlockNumber(), o.getBlockNumber());
+        return (firstCompare == 0)
+                ? Long.compare(getTransactionIndex(), o.getTransactionIndex())
+                : firstCompare;
+    }
+
     public static TxProxyBuilder builder() {
         return new TxProxyBuilder();
     }
diff --git a/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
index 53b1c2c..b309dd9 100644
--- a/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/gastracker/GasTrackerApiTests.java
@@ -1,9 +1,9 @@
 package io.goodforgod.api.etherscan.gastracker;
 
 import io.goodforgod.api.etherscan.ApiRunner;
-import io.goodforgod.api.etherscan.model.GasEstimate;
 import io.goodforgod.api.etherscan.model.GasOracle;
 import io.goodforgod.api.etherscan.model.Wei;
+import java.time.Duration;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -14,9 +14,8 @@ class GasTrackerApiTests extends ApiRunner {
 
     @Test
     void estimate() {
-        GasEstimate estimate = getApi().gasTracker().estimate(Wei.ofWei(123));
+        Duration estimate = getApi().gasTracker().estimate(Wei.ofWei(123));
         assertNotNull(estimate);
-        assertNotNull(estimate.getDuration());
     }
 
     @Test
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index f895595..efbb856 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -74,7 +74,7 @@ void gasOracleBuilder() {
                 .withSafeGasPrice(Wei.ofWei(1000000000))
                 .withGasUsedRatio(Collections.singletonList(new BigDecimal(1)))
                 .withLastBlock(1L)
-                .withSuggestBaseFee(1.0)
+                .withSuggestBaseFee(BigDecimal.valueOf(1.0))
                 .build();
 
         assertNotNull(value);
@@ -86,7 +86,7 @@ void gasOracleBuilder() {
                 .withSafeGasPrice(Wei.ofWei(1000000000))
                 .withGasUsedRatio(Collections.singletonList(new BigDecimal(1)))
                 .withLastBlock(1L)
-                .withSuggestBaseFee(1.0)
+                .withSuggestBaseFee(BigDecimal.valueOf(1.0))
                 .build();
         assertEquals(value, value2);
         assertEquals(value.hashCode(), value2.hashCode());
@@ -117,15 +117,15 @@ void logBuilder() {
     void priceBuilder() {
         LocalDateTime timestamp = LocalDateTime.now();
         Price value = Price.builder()
-                .withEthBtc(1.0)
-                .withEthUsd(1.0)
+                .withEthBtc(BigDecimal.valueOf(1.0))
+                .withEthUsd(BigDecimal.valueOf(1.0))
                 .withEthBtcTimestamp(timestamp)
                 .withEthUsdTimestamp(timestamp)
                 .build();
 
         assertNotNull(value);
-        assertEquals(1.0, value.inUsd());
-        assertEquals(1.0, value.inBtc());
+        assertEquals(BigDecimal.valueOf(1.0), value.inUsd());
+        assertEquals(BigDecimal.valueOf(1.0), value.inBtc());
     }
 
     @Test
@@ -193,6 +193,7 @@ void txBuilder() {
         assertEquals(value, value2);
         assertEquals(value.hashCode(), value2.hashCode());
         assertEquals(value.toString(), value2.toString());
+        assertEquals(0, value.compareTo(value2));
     }
 
     @Test
@@ -464,11 +465,46 @@ void blockProxyBuilder() {
     }
 
     @Test
-    void gasEstimate() {
-        GasEstimate gas1 = new GasEstimate(1);
-        GasEstimate gas2 = new GasEstimate(1);
-        assertEquals(gas1, gas2);
-        assertEquals(gas1.hashCode(), gas2.hashCode());
-        assertEquals(gas1.toString(), gas2.toString());
+    void weiTests() {
+        Wei w1 = Wei.ofWei(1);
+        Wei w2 = Wei.ofWei(1L);
+        Wei w3 = Wei.ofWei(BigInteger.valueOf(1));
+        assertEquals(w1, w2);
+        assertEquals(w1, w3);
+        assertEquals(w1.hashCode(), w2.hashCode());
+        assertEquals(w1.hashCode(), w3.hashCode());
+        assertEquals(w1.toString(), w3.toString());
+
+        Wei kw1 = Wei.ofKwei(1);
+        Wei kw2 = Wei.ofKwei(1L);
+        Wei kw3 = Wei.ofKwei(BigInteger.valueOf(1));
+        Wei kw4 = Wei.ofKwei(BigDecimal.valueOf(1));
+        assertEquals(kw1, kw2);
+        assertEquals(kw1, kw3);
+        assertEquals(kw1, kw4);
+
+        Wei mw1 = Wei.ofMwei(1);
+        Wei mw2 = Wei.ofMwei(1L);
+        Wei mw3 = Wei.ofMwei(BigInteger.valueOf(1));
+        Wei mw4 = Wei.ofMwei(BigDecimal.valueOf(1));
+        assertEquals(mw1, mw2);
+        assertEquals(mw1, mw3);
+        assertEquals(mw1, mw4);
+
+        Wei gw1 = Wei.ofGwei(1);
+        Wei gw2 = Wei.ofGwei(1L);
+        Wei gw3 = Wei.ofGwei(BigInteger.valueOf(1));
+        Wei gw4 = Wei.ofGwei(BigDecimal.valueOf(1));
+        assertEquals(gw1, gw2);
+        assertEquals(gw1, gw3);
+        assertEquals(gw1, gw4);
+
+        Wei ew1 = Wei.ofEther(1);
+        Wei ew2 = Wei.ofEther(1L);
+        Wei ew3 = Wei.ofEther(BigInteger.valueOf(1));
+        Wei ew4 = Wei.ofEther(BigDecimal.valueOf(1));
+        assertEquals(ew1, ew2);
+        assertEquals(ew1, ew3);
+        assertEquals(ew1, ew4);
     }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
index e4322f2..662fec2 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyTxReceiptApiTests.java
@@ -26,7 +26,7 @@ void correct() {
         assertNotNull(infoProxy.get().getTransactionHash());
         assertNotNull(infoProxy.get().getTransactionIndex());
         assertNotNull(infoProxy.get().getGasUsed());
-        assertNotNull(infoProxy.get().getCumulativeGasUsed());
+        assertNotNull(infoProxy.get().getGasUsedCumulative());
         assertNotNull(infoProxy.get().getLogs());
         assertNotNull(infoProxy.get().getLogsBloom());
         assertNull(infoProxy.get().getContractAddress());

From e6bee19e2affac147be8d9a1aebeab1bf5f0c293 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 May 2023 20:58:07 +0300
Subject: [PATCH 47/67] [2.0.0] BasicProvider simplified StatisticPriceApiTests
 assert fixed

---
 .../api/etherscan/BasicProvider.java          | 28 ++-----------------
 .../statistic/StatisticPriceApiTests.java     |  4 +--
 2 files changed, 4 insertions(+), 28 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 3c88f3b..5c61aad 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -1,6 +1,5 @@
 package io.goodforgod.api.etherscan;
 
-import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanParseException;
 import io.goodforgod.api.etherscan.error.EtherScanRateLimitException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
@@ -9,7 +8,6 @@
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
-import java.util.Map;
 
 /**
  * Base provider for API Implementations
@@ -64,36 +62,14 @@ <T> T convert(byte[] json, Class<T> tClass) {
             }
 
             final String jsonAsString = new String(json, StandardCharsets.UTF_8);
-            try {
-                final Map<String, Object> map = converter.fromJson(json, Map.class);
-                final Object result = map.get("result");
-                if (result instanceof String && ((String) result).startsWith(MAX_RATE_LIMIT_REACHED))
-                    throw new EtherScanRateLimitException(((String) result));
-
-                throw new EtherScanParseException(e.getMessage() + ", for response: " + jsonAsString, e.getCause(), jsonAsString);
-            } catch (EtherScanException ex) {
-                throw ex;
-            } catch (Exception ex) {
-                throw new EtherScanParseException(e.getMessage() + ", for response: " + jsonAsString, e.getCause(), jsonAsString);
-            }
+            throw new EtherScanParseException(e.getMessage() + ", for response: " + jsonAsString, e.getCause(), jsonAsString);
         }
     }
 
     byte[] getRequest(String urlParameters) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
-        final byte[] result = executor.get(uri);
-        if (result.length == 0) {
-            final StringResponseTO emptyResponse = StringResponseTO.builder()
-                    .withStatus("0")
-                    .withMessage("Server returned null value for GET request at URL - " + uri)
-                    .withResult("")
-                    .build();
-
-            throw new EtherScanResponseException(emptyResponse, "Server returned null value for GET request at URL - " + uri);
-        }
-
-        return result;
+        return executor.get(uri);
     }
 
     byte[] postRequest(String urlParameters, String dataToPost) {
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
index 0dd89c2..ffc37a9 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
@@ -16,8 +16,8 @@ void correct() {
         assertNotNull(price);
         assertNotNull(price.btcTimestamp());
         assertNotNull(price.usdTimestamp());
-        assertNotEquals(0.0, price.inBtc());
-        assertNotEquals(0.0, price.inUsd());
+        assertNotEquals(0.0, price.inBtc().doubleValue());
+        assertNotEquals(0.0, price.inUsd().doubleValue());
         assertNotNull(price.toString());
 
         Price empty = Price.builder().build();

From c64a3017f1eb99f7e4c4828de66dd9b0da0efff5 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Wed, 17 May 2023 00:04:51 +0300
Subject: [PATCH 48/67] [2.0.0] Javadoc improved

---
 README.md                                     |  4 +-
 .../goodforgod/api/etherscan/AccountAPI.java  | 62 +++++++++--------
 .../api/etherscan/AccountAPIProvider.java     | 68 ++++++++++---------
 .../goodforgod/api/etherscan/ContractAPI.java |  2 +-
 .../api/etherscan/ContractAPIProvider.java    |  2 +-
 .../io/goodforgod/api/etherscan/LogsAPI.java  |  2 +-
 .../api/etherscan/LogsAPIProvider.java        |  2 +-
 .../io/goodforgod/api/etherscan/ProxyAPI.java | 16 ++---
 .../api/etherscan/ProxyAPIProvider.java       | 16 ++---
 .../api/etherscan/StatisticAPI.java           |  2 +-
 .../api/etherscan/StatisticAPIProvider.java   |  2 +-
 .../api/etherscan/TransactionAPI.java         |  4 +-
 .../api/etherscan/TransactionAPIProvider.java |  4 +-
 .../goodforgod/api/etherscan/model/Block.java |  4 --
 .../goodforgod/api/etherscan/model/Price.java | 20 +++---
 .../etherscan/model/ModelBuilderTests.java    |  8 +--
 .../statistic/StatisticPriceApiTests.java     |  4 +-
 17 files changed, 114 insertions(+), 108 deletions(-)

diff --git a/README.md b/README.md
index dc939bf..dd244b5 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,9 @@
 [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
 [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=ncloc)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
 
-[Etherscan.io](https://etherscan.io/apis) Java API implementation.
+[Etherscan.io](https://docs.etherscan.io/) Java API implementation.
 
-Library supports all available EtherScan *API* calls for all available *Ethereum Networks* for *etherscan.io*
+Library supports EtherScan *API* for all available *Ethereum Networks* for *etherscan.io*
 
 ## Dependency :rocket:
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
index 45be8b8..09c49eb 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPI.java
@@ -21,7 +21,7 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Balance balance(String address) throws EtherScanException;
+    Balance balance(@NotNull String address) throws EtherScanException;
 
     /**
      * ERC20 token balance for address
@@ -32,7 +32,7 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    TokenBalance balance(String address, String contract) throws EtherScanException;
+    TokenBalance balance(@NotNull String address, @NotNull String contract) throws EtherScanException;
 
     /**
      * Maximum 20 address for single batch request If address MORE THAN 20, then there will be more than
@@ -43,7 +43,7 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<Balance> balances(List<String> addresses) throws EtherScanException;
+    List<Balance> balances(@NotNull List<String> addresses) throws EtherScanException;
 
     /**
      * All txs for given address
@@ -55,13 +55,13 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<Tx> txs(String address, long startBlock, long endBlock) throws EtherScanException;
+    List<Tx> txs(@NotNull String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<Tx> txs(String address, long startBlock) throws EtherScanException;
+    List<Tx> txs(@NotNull String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<Tx> txs(String address) throws EtherScanException;
+    List<Tx> txs(@NotNull String address) throws EtherScanException;
 
     /**
      * All internal txs for given address
@@ -73,13 +73,13 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxInternal> txsInternal(String address, long startBlock, long endBlock) throws EtherScanException;
+    List<TxInternal> txsInternal(@NotNull String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxInternal> txsInternal(String address, long startBlock) throws EtherScanException;
+    List<TxInternal> txsInternal(@NotNull String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxInternal> txsInternal(String address) throws EtherScanException;
+    List<TxInternal> txsInternal(@NotNull String address) throws EtherScanException;
 
     /**
      * All internal tx for given transaction hash
@@ -89,7 +89,7 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxInternal> txsInternalByHash(String txhash) throws EtherScanException;
+    List<TxInternal> txsInternalByHash(@NotNull String txhash) throws EtherScanException;
 
     /**
      * All ERC-20 token txs for given address
@@ -101,13 +101,13 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxErc20> txsErc20(String address, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(@NotNull String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc20> txsErc20(String address, long startBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(@NotNull String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc20> txsErc20(String address) throws EtherScanException;
+    List<TxErc20> txsErc20(@NotNull String address) throws EtherScanException;
 
     /**
      * All ERC-20 token txs for given address and contract address
@@ -120,13 +120,14 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxErc20> txsErc20(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(@NotNull String address, @NotNull String contractAddress, long startBlock, long endBlock)
+            throws EtherScanException;
 
     @NotNull
-    List<TxErc20> txsErc20(String address, String contractAddress, long startBlock) throws EtherScanException;
+    List<TxErc20> txsErc20(@NotNull String address, @NotNull String contractAddress, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc20> txsErc20(String address, String contractAddress) throws EtherScanException;
+    List<TxErc20> txsErc20(@NotNull String address, @NotNull String contractAddress) throws EtherScanException;
 
     /**
      * All ERC-721 (NFT) token txs for given address
@@ -138,13 +139,13 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxErc721> txsErc721(String address, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc721> txsErc721(@NotNull String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc721> txsErc721(String address, long startBlock) throws EtherScanException;
+    List<TxErc721> txsErc721(@NotNull String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc721> txsErc721(String address) throws EtherScanException;
+    List<TxErc721> txsErc721(@NotNull String address) throws EtherScanException;
 
     /**
      * All ERC-721 (NFT) token txs for given address
@@ -156,13 +157,14 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxErc721> txsErc721(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc721> txsErc721(@NotNull String address, @NotNull String contractAddress, long startBlock, long endBlock)
+            throws EtherScanException;
 
     @NotNull
-    List<TxErc721> txsErc721(String address, String contractAddress, long startBlock) throws EtherScanException;
+    List<TxErc721> txsErc721(@NotNull String address, @NotNull String contractAddress, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc721> txsErc721(String address, String contractAddress) throws EtherScanException;
+    List<TxErc721> txsErc721(@NotNull String address, @NotNull String contractAddress) throws EtherScanException;
 
     /**
      * All ERC-721 (NFT) token txs for given address
@@ -174,13 +176,13 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxErc1155> txsErc1155(String address, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc1155> txsErc1155(@NotNull String address, long startBlock, long endBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc1155> txsErc1155(String address, long startBlock) throws EtherScanException;
+    List<TxErc1155> txsErc1155(@NotNull String address, long startBlock) throws EtherScanException;
 
     @NotNull
-    List<TxErc1155> txsErc1155(String address) throws EtherScanException;
+    List<TxErc1155> txsErc1155(@NotNull String address) throws EtherScanException;
 
     /**
      * All ERC-721 (NFT) token txs for given address
@@ -192,13 +194,15 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock, long endBlock) throws EtherScanException;
+    List<TxErc1155> txsErc1155(@NotNull String address, @NotNull String contractAddress, long startBlock, long endBlock)
+            throws EtherScanException;
 
     @NotNull
-    List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock) throws EtherScanException;
+    List<TxErc1155> txsErc1155(@NotNull String address, @NotNull String contractAddress, long startBlock)
+            throws EtherScanException;
 
     @NotNull
-    List<TxErc1155> txsErc1155(String address, String contractAddress) throws EtherScanException;
+    List<TxErc1155> txsErc1155(@NotNull String address, @NotNull String contractAddress) throws EtherScanException;
 
     /**
      * All blocks mined by address
@@ -208,5 +212,5 @@ public interface AccountAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    List<Block> blocksMined(String address) throws EtherScanException;
+    List<Block> blocksMined(@NotNull String address) throws EtherScanException;
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 08e9dd5..442edff 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -56,7 +56,7 @@ final class AccountAPIProvider extends BasicProvider implements AccountAPI {
 
     @NotNull
     @Override
-    public Balance balance(String address) throws EtherScanException {
+    public Balance balance(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_BALANCE_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + address;
@@ -69,7 +69,7 @@ public Balance balance(String address) throws EtherScanException {
 
     @NotNull
     @Override
-    public TokenBalance balance(String address, String contract) throws EtherScanException {
+    public TokenBalance balance(@NotNull String address, @NotNull String contract) throws EtherScanException {
         BasicUtils.validateAddress(address);
         BasicUtils.validateAddress(contract);
 
@@ -83,7 +83,7 @@ public TokenBalance balance(String address, String contract) throws EtherScanExc
 
     @NotNull
     @Override
-    public List<Balance> balances(List<String> addresses) throws EtherScanException {
+    public List<Balance> balances(@NotNull List<String> addresses) throws EtherScanException {
         if (BasicUtils.isEmpty(addresses)) {
             return Collections.emptyList();
         }
@@ -117,19 +117,19 @@ private String toAddressParam(List<String> addresses) {
 
     @NotNull
     @Override
-    public List<Tx> txs(String address) throws EtherScanException {
+    public List<Tx> txs(@NotNull String address) throws EtherScanException {
         return txs(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<Tx> txs(String address, long startBlock) throws EtherScanException {
+    public List<Tx> txs(@NotNull String address, long startBlock) throws EtherScanException {
         return txs(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<Tx> txs(String address, long startBlock, long endBlock) throws EtherScanException {
+    public List<Tx> txs(@NotNull String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
@@ -171,19 +171,19 @@ private <T, R extends BaseListResponseTO<T>> List<T> getRequestUsingOffset(final
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternal(String address) throws EtherScanException {
+    public List<TxInternal> txsInternal(@NotNull String address) throws EtherScanException {
         return txsInternal(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternal(String address, long startBlock) throws EtherScanException {
+    public List<TxInternal> txsInternal(@NotNull String address, long startBlock) throws EtherScanException {
         return txsInternal(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternal(String address, long startBlock, long endBlock)
+    public List<TxInternal> txsInternal(@NotNull String address, long startBlock, long endBlock)
             throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
@@ -198,7 +198,7 @@ public List<TxInternal> txsInternal(String address, long startBlock, long endBlo
 
     @NotNull
     @Override
-    public List<TxInternal> txsInternalByHash(String txhash) throws EtherScanException {
+    public List<TxInternal> txsInternalByHash(@NotNull String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_INTERNAL_ACTION + TXHASH_PARAM + txhash;
@@ -212,19 +212,19 @@ public List<TxInternal> txsInternalByHash(String txhash) throws EtherScanExcepti
 
     @NotNull
     @Override
-    public List<TxErc20> txsErc20(String address) throws EtherScanException {
+    public List<TxErc20> txsErc20(@NotNull String address) throws EtherScanException {
         return txsErc20(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxErc20> txsErc20(String address, long startBlock) throws EtherScanException {
+    public List<TxErc20> txsErc20(@NotNull String address, long startBlock) throws EtherScanException {
         return txsErc20(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxErc20> txsErc20(String address, long startBlock, long endBlock) throws EtherScanException {
+    public List<TxErc20> txsErc20(@NotNull String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
@@ -238,19 +238,20 @@ public List<TxErc20> txsErc20(String address, long startBlock, long endBlock) th
 
     @NotNull
     @Override
-    public List<TxErc20> txsErc20(String address, String contractAddress) throws EtherScanException {
+    public List<TxErc20> txsErc20(@NotNull String address, @NotNull String contractAddress) throws EtherScanException {
         return txsErc20(address, contractAddress, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxErc20> txsErc20(String address, String contractAddress, long startBlock) throws EtherScanException {
+    public List<TxErc20> txsErc20(@NotNull String address, @NotNull String contractAddress, long startBlock)
+            throws EtherScanException {
         return txsErc20(address, contractAddress, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxErc20> txsErc20(String address, String contractAddress, long startBlock, long endBlock)
+    public List<TxErc20> txsErc20(@NotNull String address, @NotNull String contractAddress, long startBlock, long endBlock)
             throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
@@ -265,19 +266,19 @@ public List<TxErc20> txsErc20(String address, String contractAddress, long start
 
     @NotNull
     @Override
-    public List<TxErc721> txsErc721(String address) throws EtherScanException {
+    public List<TxErc721> txsErc721(@NotNull String address) throws EtherScanException {
         return txsErc721(address, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxErc721> txsErc721(String address, long startBlock) throws EtherScanException {
+    public List<TxErc721> txsErc721(@NotNull String address, long startBlock) throws EtherScanException {
         return txsErc721(address, startBlock, MAX_END_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<TxErc721> txsErc721(String address, long startBlock, long endBlock) throws EtherScanException {
+    public List<TxErc721> txsErc721(@NotNull String address, long startBlock, long endBlock) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
@@ -290,8 +291,9 @@ public List<TxErc721> txsErc721(String address, long startBlock, long endBlock)
     }
 
     @Override
-    public @NotNull List<TxErc721> txsErc721(String address, String contractAddress, long startBlock, long endBlock)
-            throws EtherScanException {
+    public @NotNull List<TxErc721>
+            txsErc721(@NotNull String address, @NotNull String contractAddress, long startBlock, long endBlock)
+                    throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
@@ -304,17 +306,19 @@ public List<TxErc721> txsErc721(String address, long startBlock, long endBlock)
     }
 
     @Override
-    public @NotNull List<TxErc721> txsErc721(String address, String contractAddress, long startBlock) throws EtherScanException {
+    public @NotNull List<TxErc721> txsErc721(@NotNull String address, @NotNull String contractAddress, long startBlock)
+            throws EtherScanException {
         return txsErc721(address, contractAddress, startBlock, MAX_END_BLOCK);
     }
 
     @Override
-    public @NotNull List<TxErc721> txsErc721(String address, String contractAddress) throws EtherScanException {
+    public @NotNull List<TxErc721> txsErc721(@NotNull String address, @NotNull String contractAddress) throws EtherScanException {
         return txsErc721(address, contractAddress, MIN_START_BLOCK);
     }
 
     @Override
-    public @NotNull List<TxErc1155> txsErc1155(String address, long startBlock, long endBlock) throws EtherScanException {
+    public @NotNull List<TxErc1155> txsErc1155(@NotNull String address, long startBlock, long endBlock)
+            throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
@@ -327,18 +331,19 @@ public List<TxErc721> txsErc721(String address, long startBlock, long endBlock)
     }
 
     @Override
-    public @NotNull List<TxErc1155> txsErc1155(String address, long startBlock) throws EtherScanException {
+    public @NotNull List<TxErc1155> txsErc1155(@NotNull String address, long startBlock) throws EtherScanException {
         return txsErc1155(address, startBlock, MAX_END_BLOCK);
     }
 
     @Override
-    public @NotNull List<TxErc1155> txsErc1155(String address) throws EtherScanException {
+    public @NotNull List<TxErc1155> txsErc1155(@NotNull String address) throws EtherScanException {
         return txsErc1155(address, MIN_START_BLOCK);
     }
 
     @Override
-    public @NotNull List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock, long endBlock)
-            throws EtherScanException {
+    public @NotNull List<TxErc1155>
+            txsErc1155(@NotNull String address, @NotNull String contractAddress, long startBlock, long endBlock)
+                    throws EtherScanException {
         BasicUtils.validateAddress(address);
         final BlockParam blocks = BasicUtils.compensateBlocks(startBlock, endBlock);
 
@@ -351,19 +356,20 @@ public List<TxErc721> txsErc721(String address, long startBlock, long endBlock)
     }
 
     @Override
-    public @NotNull List<TxErc1155> txsErc1155(String address, String contractAddress, long startBlock)
+    public @NotNull List<TxErc1155> txsErc1155(@NotNull String address, @NotNull String contractAddress, long startBlock)
             throws EtherScanException {
         return txsErc1155(address, contractAddress, startBlock, MAX_END_BLOCK);
     }
 
     @Override
-    public @NotNull List<TxErc1155> txsErc1155(String address, String contractAddress) throws EtherScanException {
+    public @NotNull List<TxErc1155> txsErc1155(@NotNull String address, @NotNull String contractAddress)
+            throws EtherScanException {
         return txsErc1155(address, contractAddress, MIN_START_BLOCK);
     }
 
     @NotNull
     @Override
-    public List<Block> blocksMined(String address) throws EtherScanException {
+    public List<Block> blocksMined(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_MINED_ACTION + PAGE_PARAM + "%s" + OFFSET_PARAM + OFFSET_MAX + BLOCK_TYPE_PARAM
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
index 7564c98..af0852c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
@@ -20,5 +20,5 @@ public interface ContractAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Abi contractAbi(String address) throws EtherScanException;
+    Abi contractAbi(@NotNull String address) throws EtherScanException;
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index bbb7335..6b4404a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -31,7 +31,7 @@ final class ContractAPIProvider extends BasicProvider implements ContractAPI {
 
     @NotNull
     @Override
-    public Abi contractAbi(String address) throws EtherScanException {
+    public Abi contractAbi(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParam = ACT_ABI_PARAM + ADDRESS_PARAM + address;
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
index 01d79f7..0330f9f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPI.java
@@ -23,5 +23,5 @@ public interface LogsAPI {
      * @see LogQuery
      */
     @NotNull
-    List<Log> logs(LogQuery query) throws EtherScanException;
+    List<Log> logs(@NotNull LogQuery query) throws EtherScanException;
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
index fe9d420..d294fb5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
@@ -31,7 +31,7 @@ final class LogsAPIProvider extends BasicProvider implements LogsAPI {
 
     @NotNull
     @Override
-    public List<Log> logs(LogQuery query) throws EtherScanException {
+    public List<Log> logs(@NotNull LogQuery query) throws EtherScanException {
         final String urlParams = ACT_LOGS_PARAM + query.params();
         final LogResponseTO response = getRequest(urlParams, LogResponseTO.class);
         BasicUtils.validateTxResponse(response);
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
index 77d6769..30c4f96 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPI.java
@@ -56,7 +56,7 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<TxProxy> tx(String txhash) throws EtherScanException;
+    Optional<TxProxy> tx(@NotNull String txhash) throws EtherScanException;
 
     /**
      * Returns information about a transaction by block number and transaction index position
@@ -87,7 +87,7 @@ public interface ProxyAPI {
      * @return transactions send amount from address
      * @throws EtherScanException parent exception class
      */
-    int txSendCount(String address) throws EtherScanException;
+    int txSendCount(@NotNull String address) throws EtherScanException;
 
     /**
      * Creates new message call transaction or a contract creation for signed transactions
@@ -98,7 +98,7 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<String> txSendRaw(String hexEncodedTx) throws EtherScanException;
+    Optional<String> txSendRaw(@NotNull String hexEncodedTx) throws EtherScanException;
 
     /**
      * Returns the receipt of a transaction by transaction hash eth_getTransactionReceipt
@@ -108,7 +108,7 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<ReceiptProxy> txReceipt(String txhash) throws EtherScanException;
+    Optional<ReceiptProxy> txReceipt(@NotNull String txhash) throws EtherScanException;
 
     /**
      * Executes a new message call immediately without creating a transaction on the block chain
@@ -120,7 +120,7 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<String> call(String address, String data) throws EtherScanException;
+    Optional<String> call(@NotNull String address, @NotNull String data) throws EtherScanException;
 
     /**
      * Returns code at a given address eth_getCode
@@ -130,7 +130,7 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<String> code(String address) throws EtherScanException;
+    Optional<String> code(@NotNull String address) throws EtherScanException;
 
     /**
      * (**experimental) Returns the value from a storage position at a given address eth_getStorageAt
@@ -142,7 +142,7 @@ public interface ProxyAPI {
      */
     @Experimental
     @NotNull
-    Optional<String> storageAt(String address, long position) throws EtherScanException;
+    Optional<String> storageAt(@NotNull String address, long position) throws EtherScanException;
 
     /**
      * Returns the current price per gas in wei eth_gasPrice
@@ -162,7 +162,7 @@ public interface ProxyAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Wei gasEstimated(String hexData) throws EtherScanException;
+    Wei gasEstimated(@NotNull String hexData) throws EtherScanException;
 
     @NotNull
     Wei gasEstimated() throws EtherScanException;
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index 18edd90..4dff589 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -96,7 +96,7 @@ public Optional<BlockProxy> blockUncle(long blockNo, long index) throws EtherSca
 
     @NotNull
     @Override
-    public Optional<TxProxy> tx(String txhash) throws EtherScanException {
+    public Optional<TxProxy> tx(@NotNull String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_BY_HASH_PARAM + TXHASH_PARAM + txhash;
@@ -127,7 +127,7 @@ public int txCount(long blockNo) throws EtherScanException {
     }
 
     @Override
-    public int txSendCount(String address) throws EtherScanException {
+    public int txSendCount(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_TX_COUNT_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
@@ -137,7 +137,7 @@ public int txSendCount(String address) throws EtherScanException {
 
     @Override
     @NotNull
-    public Optional<String> txSendRaw(String hexEncodedTx) throws EtherScanException {
+    public Optional<String> txSendRaw(@NotNull String hexEncodedTx) throws EtherScanException {
         if (BasicUtils.isNotHex(hexEncodedTx))
             throw new EtherScanInvalidDataHexException("Data is not encoded in hex format - " + hexEncodedTx);
 
@@ -160,7 +160,7 @@ public Optional<String> txSendRaw(String hexEncodedTx) throws EtherScanException
 
     @NotNull
     @Override
-    public Optional<ReceiptProxy> txReceipt(String txhash) throws EtherScanException {
+    public Optional<ReceiptProxy> txReceipt(@NotNull String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_RECEIPT_PARAM + TXHASH_PARAM + txhash;
@@ -170,7 +170,7 @@ public Optional<ReceiptProxy> txReceipt(String txhash) throws EtherScanException
 
     @NotNull
     @Override
-    public Optional<String> call(String address, String data) throws EtherScanException {
+    public Optional<String> call(@NotNull String address, @NotNull String data) throws EtherScanException {
         BasicUtils.validateAddress(address);
         if (BasicUtils.isNotHex(data))
             throw new EtherScanInvalidDataHexException("Data is not hex encoded.");
@@ -182,7 +182,7 @@ public Optional<String> call(String address, String data) throws EtherScanExcept
 
     @NotNull
     @Override
-    public Optional<String> code(String address) throws EtherScanException {
+    public Optional<String> code(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_CODE_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
@@ -192,7 +192,7 @@ public Optional<String> code(String address) throws EtherScanException {
 
     @NotNull
     @Override
-    public Optional<String> storageAt(String address, long position) throws EtherScanException {
+    public Optional<String> storageAt(@NotNull String address, long position) throws EtherScanException {
         BasicUtils.validateAddress(address);
         final long compPosition = BasicUtils.compensateMinBlock(position);
 
@@ -220,7 +220,7 @@ public Wei gasEstimated() throws EtherScanException {
 
     @NotNull
     @Override
-    public Wei gasEstimated(String hexData) throws EtherScanException {
+    public Wei gasEstimated(@NotNull String hexData) throws EtherScanException {
         if (!BasicUtils.isEmpty(hexData) && BasicUtils.isNotHex(hexData))
             throw new EtherScanInvalidDataHexException("Data is not in hex format.");
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
index 10e41e3..0a39eae 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
@@ -24,7 +24,7 @@ public interface StatisticAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Wei supply(String contract) throws EtherScanException;
+    Wei supply(@NotNull String contract) throws EtherScanException;
 
     /**
      * Returns the current amount of Ether in circulation excluding ETH2 Staking rewards and EIP1559
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
index 9555169..131df71 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
@@ -58,7 +58,7 @@ public Wei supply() throws EtherScanException {
 
     @NotNull
     @Override
-    public Wei supply(String contract) throws EtherScanException {
+    public Wei supply(@NotNull String contract) throws EtherScanException {
         BasicUtils.validateAddress(contract);
 
         final String urlParams = ACT_TOKEN_SUPPLY_PARAM + CONTRACT_ADDRESS_PARAM + contract;
diff --git a/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
index a89a4a6..c719e5b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPI.java
@@ -21,7 +21,7 @@ public interface TransactionAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<Status> statusExec(String txhash) throws EtherScanException;
+    Optional<Status> statusExec(@NotNull String txhash) throws EtherScanException;
 
     /**
      * Check Transaction Receipt Status (Only applicable for Post Byzantium fork transactions)
@@ -31,5 +31,5 @@ public interface TransactionAPI {
      * @throws EtherScanException parent exception class
      */
     @NotNull
-    Optional<Boolean> statusReceipt(String txhash) throws EtherScanException;
+    Optional<Boolean> statusReceipt(@NotNull String txhash) throws EtherScanException;
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
index c131079..da26b51 100644
--- a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
@@ -33,7 +33,7 @@ final class TransactionAPIProvider extends BasicProvider implements TransactionA
 
     @NotNull
     @Override
-    public Optional<Status> statusExec(String txhash) throws EtherScanException {
+    public Optional<Status> statusExec(@NotNull String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_EXEC_STATUS_PARAM + TXHASH_PARAM + txhash;
@@ -45,7 +45,7 @@ public Optional<Status> statusExec(String txhash) throws EtherScanException {
 
     @NotNull
     @Override
-    public Optional<Boolean> statusReceipt(String txhash) throws EtherScanException {
+    public Optional<Boolean> statusReceipt(@NotNull String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_RECEIPT_STATUS_PARAM + TXHASH_PARAM + txhash;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Block.java b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
index 9fe4e02..0550000 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Block.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
@@ -79,10 +79,6 @@ public static class BlockBuilder {
 
         BlockBuilder() {}
 
-        public static BlockBuilder aBlock() {
-            return new BlockBuilder();
-        }
-
         public BlockBuilder withBlockNumber(long blockNumber) {
             this.blockNumber = blockNumber;
             return this;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
index d2a8091..565dbed 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -31,14 +31,14 @@ public BigDecimal inBtc() {
         return ethbtc;
     }
 
-    public LocalDateTime usdTimestamp() {
+    public LocalDateTime timestampUsd() {
         if (_ethusd_timestamp == null && ethusd_timestamp != null) {
             _ethusd_timestamp = LocalDateTime.ofEpochSecond(Long.parseLong(ethusd_timestamp), 0, ZoneOffset.UTC);
         }
         return _ethusd_timestamp;
     }
 
-    public LocalDateTime btcTimestamp() {
+    public LocalDateTime timestampBtc() {
         if (_ethbtc_timestamp == null && ethbtc_timestamp != null) {
             _ethbtc_timestamp = LocalDateTime.ofEpochSecond(Long.parseLong(ethbtc_timestamp), 0, ZoneOffset.UTC);
         }
@@ -85,23 +85,23 @@ public static final class PriceBuilder {
 
         private PriceBuilder() {}
 
-        public PriceBuilder withEthUsd(BigDecimal ethusd) {
-            this.ethusd = ethusd;
+        public PriceBuilder withUsd(BigDecimal ethToUsd) {
+            this.ethusd = ethToUsd;
             return this;
         }
 
-        public PriceBuilder withEthBtc(BigDecimal ethbtc) {
-            this.ethbtc = ethbtc;
+        public PriceBuilder withBtc(BigDecimal ethToBtc) {
+            this.ethbtc = ethToBtc;
             return this;
         }
 
-        public PriceBuilder withEthUsdTimestamp(LocalDateTime ethusdTimestamp) {
-            this.ethusdTimestamp = ethusdTimestamp;
+        public PriceBuilder withTimestampUsd(LocalDateTime ethToUsdTimestamp) {
+            this.ethusdTimestamp = ethToUsdTimestamp;
             return this;
         }
 
-        public PriceBuilder withEthBtcTimestamp(LocalDateTime ethbtcTimestamp) {
-            this.ethbtcTimestamp = ethbtcTimestamp;
+        public PriceBuilder withTimestampBtc(LocalDateTime ethToBtcTimestamp) {
+            this.ethbtcTimestamp = ethToBtcTimestamp;
             return this;
         }
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
index efbb856..8f9a728 100644
--- a/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/model/ModelBuilderTests.java
@@ -117,10 +117,10 @@ void logBuilder() {
     void priceBuilder() {
         LocalDateTime timestamp = LocalDateTime.now();
         Price value = Price.builder()
-                .withEthBtc(BigDecimal.valueOf(1.0))
-                .withEthUsd(BigDecimal.valueOf(1.0))
-                .withEthBtcTimestamp(timestamp)
-                .withEthUsdTimestamp(timestamp)
+                .withBtc(BigDecimal.valueOf(1.0))
+                .withUsd(BigDecimal.valueOf(1.0))
+                .withTimestampBtc(timestamp)
+                .withTimestampUsd(timestamp)
                 .build();
 
         assertNotNull(value);
diff --git a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
index ffc37a9..76b87d5 100644
--- a/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/statistic/StatisticPriceApiTests.java
@@ -14,8 +14,8 @@ class StatisticPriceApiTests extends ApiRunner {
     void correct() {
         Price price = getApi().stats().priceLast();
         assertNotNull(price);
-        assertNotNull(price.btcTimestamp());
-        assertNotNull(price.usdTimestamp());
+        assertNotNull(price.timestampBtc());
+        assertNotNull(price.timestampUsd());
         assertNotEquals(0.0, price.inBtc().doubleValue());
         assertNotEquals(0.0, price.inUsd().doubleValue());
         assertNotNull(price.toString());

From 0e1dcccea1c3723fe39fe40871341b2dc946265a Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Thu, 18 May 2023 01:11:42 +0300
Subject: [PATCH 49/67] [2.0.0] Javadoc fixed

---
 src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
index 0a39eae..d7b48b8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
@@ -15,9 +15,7 @@
 public interface StatisticAPI {
 
     /**
-     * ERC20 token total Supply
-     * <a href=
-     * "https://docs.etherscan.io/api-endpoints/tokens#get-erc20-token-totalsupply-by-contractaddress">EtherScan<a>
+     * Returns the current amount of an ERC-20 token in circulation.
      *
      * @param contract contract address
      * @return token supply for specified contract

From 333cfe4e4a08fb8c45973327370abb253a83c44b Mon Sep 17 00:00:00 2001
From: Blackmorse <blackmorse@live.com>
Date: Mon, 25 Sep 2023 00:02:09 +0400
Subject: [PATCH 50/67] Contract creation API

---
 .../api/etherscan/AccountAPIProvider.java     |  6 +-
 .../goodforgod/api/etherscan/ContractAPI.java | 11 +++
 .../api/etherscan/ContractAPIProvider.java    | 30 +++++++
 .../api/etherscan/model/ContractCreation.java | 80 +++++++++++++++++++
 .../response/ContractCreationResponseTO.java  |  4 +
 .../model/response/ContractCreationTO.java    | 20 +++++
 .../api/etherscan/util/BasicUtils.java        |  4 +
 .../etherscan/contract/ContractApiTests.java  | 46 +++++++++++
 8 files changed, 196 insertions(+), 5 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationTO.java

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 442edff..d36baf7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -95,7 +95,7 @@ public List<Balance> balances(@NotNull List<String> addresses) throws EtherScanE
         final List<List<String>> addressesAsBatches = BasicUtils.partition(addresses, 20);
 
         for (final List<String> batch : addressesAsBatches) {
-            final String urlParams = ACT_BALANCE_MULTI_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + toAddressParam(batch);
+            final String urlParams = ACT_BALANCE_MULTI_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + BasicUtils.toAddressParam(batch);
             final BalanceResponseTO response = getRequest(urlParams, BalanceResponseTO.class);
             if (response.getStatus() != 1) {
                 throw new EtherScanResponseException(response);
@@ -111,10 +111,6 @@ public List<Balance> balances(@NotNull List<String> addresses) throws EtherScanE
         return balances;
     }
 
-    private String toAddressParam(List<String> addresses) {
-        return String.join(",", addresses);
-    }
-
     @NotNull
     @Override
     public List<Tx> txs(@NotNull String address) throws EtherScanException {
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
index af0852c..45ecb1e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
@@ -2,8 +2,11 @@
 
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.model.Abi;
+import io.goodforgod.api.etherscan.model.ContractCreation;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.List;
+
 /**
  * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/contracts">...</a>
  *
@@ -21,4 +24,12 @@ public interface ContractAPI {
      */
     @NotNull
     Abi contractAbi(@NotNull String address) throws EtherScanException;
+
+    /**
+     * Returns a contract's deployer address and transaction hash it was created, up to 5 at a time.
+     * @param contractAddresses - list of addresses to fetch
+     * @throws EtherScanException parent exception class
+     */
+    @NotNull
+    List<ContractCreation> contractCreation(@NotNull List<String> contractAddresses) throws EtherScanException;
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index 6b4404a..fda1b0d 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -5,10 +5,15 @@
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.Abi;
+import io.goodforgod.api.etherscan.model.ContractCreation;
+import io.goodforgod.api.etherscan.model.response.ContractCreationResponseTO;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 /**
  * Contract API Implementation
  *
@@ -22,6 +27,12 @@ final class ContractAPIProvider extends BasicProvider implements ContractAPI {
 
     private static final String ADDRESS_PARAM = "&address=";
 
+    private static final String ACT_CONTRACT_CREATION_PARAM = "getcontractcreation";
+
+    private static final String ACT_CONTRACT_CREATION = ACT_PREFIX + ACT_CONTRACT_CREATION_PARAM;
+
+    private static final String ACT_CONTRACT_ADDRESSES_PARAM = "&contractaddresses=";
+
     ContractAPIProvider(RequestQueueManager requestQueueManager,
                         String baseUrl,
                         EthHttpClient executor,
@@ -44,4 +55,23 @@ public Abi contractAbi(@NotNull String address) throws EtherScanException {
                 ? Abi.nonVerified()
                 : Abi.verified(response.getResult());
     }
+
+    @NotNull
+    @Override
+    public List<ContractCreation> contractCreation(@NotNull List<String> contractAddresses) throws EtherScanException {
+        BasicUtils.validateAddresses(contractAddresses);
+        final String urlParam = ACT_CONTRACT_CREATION + ACT_CONTRACT_ADDRESSES_PARAM + BasicUtils.toAddressParam(contractAddresses);
+        final ContractCreationResponseTO response = getRequest(urlParam, ContractCreationResponseTO.class);
+        if (response.getStatus() != 1 && response.getMessage().startsWith("NOTOK")) {
+            throw new EtherScanResponseException(response);
+        }
+
+        return response.getResult().stream()
+                .map(to -> ContractCreation.builder()
+                        .withContractCreator(to.getContractCreator())
+                        .withContractAddress(to.getContractAddress())
+                        .withTxHash(to.getTxHash())
+                        .build()
+                ).collect(Collectors.toList());
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
new file mode 100644
index 0000000..747aefb
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
@@ -0,0 +1,80 @@
+package io.goodforgod.api.etherscan.model;
+
+import java.util.Objects;
+
+public class ContractCreation {
+    private final String contractAddress;
+    private final String contractCreator;
+    private final String txHash;
+
+    private ContractCreation(String contractAddress, String contractCreator, String txHash) {
+        this.contractAddress = contractAddress;
+        this.contractCreator = contractCreator;
+        this.txHash = txHash;
+    }
+
+    public String getContractAddress() {
+        return contractAddress;
+    }
+
+    public String getContractCreator() {
+        return contractCreator;
+    }
+
+    public String getTxHash() {
+        return txHash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ContractCreation that = (ContractCreation) o;
+        return Objects.equals(contractAddress, that.contractAddress) && Objects.equals(contractCreator, that.contractCreator) && Objects.equals(txHash, that.txHash);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(contractAddress, contractCreator, txHash);
+    }
+
+    @Override
+    public String toString() {
+        return "ContractCreation{" +
+                "contractAddress='" + contractAddress + '\'' +
+                ", contractCreator='" + contractCreator + '\'' +
+                ", txHash='" + txHash + '\'' +
+                '}';
+    }
+
+    public static ContractCreationBuilder builder() {
+        return new ContractCreationBuilder();
+    }
+
+    public static final class ContractCreationBuilder {
+        private String contractAddress;
+        private String contractCreator;
+        private String txHash;
+
+        private ContractCreationBuilder() {}
+
+        public ContractCreationBuilder withContractAddress(String contractAddress) {
+            this.contractAddress = contractAddress;
+            return this;
+        }
+
+        public ContractCreationBuilder withContractCreator(String contractCreator) {
+            this.contractCreator = contractCreator;
+            return this;
+        }
+
+        public ContractCreationBuilder withTxHash(String txHash) {
+            this.txHash = txHash;
+            return this;
+        }
+
+        public ContractCreation build() {
+            return new ContractCreation(contractAddress, contractCreator, txHash);
+        }
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java
new file mode 100644
index 0000000..7cf28fc
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java
@@ -0,0 +1,4 @@
+package io.goodforgod.api.etherscan.model.response;
+
+public class ContractCreationResponseTO extends BaseListResponseTO<ContractCreationTO> {
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationTO.java
new file mode 100644
index 0000000..9e1551e
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationTO.java
@@ -0,0 +1,20 @@
+package io.goodforgod.api.etherscan.model.response;
+
+public class ContractCreationTO {
+
+    private String contractAddress;
+    private String contractCreator;
+    private String txHash;
+
+    public String getContractAddress() {
+        return contractAddress;
+    }
+
+    public String getContractCreator() {
+        return contractCreator;
+    }
+
+    public String getTxHash() {
+        return txHash;
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
index 216ab62..916d4ab 100644
--- a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
+++ b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
@@ -149,4 +149,8 @@ public static List<List<String>> partition(List<String> list, int pairSize) {
 
         return partitioned;
     }
+
+    public static String toAddressParam(List<String> addresses) {
+        return String.join(",", addresses);
+    }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
index 4fd0fdb..49e8f07 100644
--- a/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
@@ -3,8 +3,13 @@
 import io.goodforgod.api.etherscan.ApiRunner;
 import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
 import io.goodforgod.api.etherscan.model.Abi;
+import io.goodforgod.api.etherscan.model.ContractCreation;
 import org.junit.jupiter.api.Test;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * @author GoodforGod
  * @since 03.11.2018
@@ -37,4 +42,45 @@ void correctParamWithEmptyExpectedResult() {
         assertNotNull(abi);
         assertTrue(abi.isVerified());
     }
+
+    @Test
+    void correctContractCreation() {
+        List<ContractCreation> contractCreations =
+                getApi().contract().contractCreation(Collections.singletonList("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413"));
+
+        assertEquals(1, contractCreations.size());
+        ContractCreation contractCreation = contractCreations.get(0);
+
+        assertEquals("0xbb9bc244d798123fde783fcc1c72d3bb8c189413", contractCreation.getContractAddress());
+        assertEquals("0x793ea9692ada1900fbd0b80fffec6e431fe8b391", contractCreation.getContractCreator());
+        assertEquals("0xe9ebfecc2fa10100db51a4408d18193b3ac504584b51a4e55bdef1318f0a30f9", contractCreation.getTxHash());
+    }
+
+    @Test
+    void correctMultipleContractCreation() {
+        List<ContractCreation> contractCreations =
+                getApi().contract().contractCreation(Arrays.asList("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413", "0x5EaC95ad5b287cF44E058dCf694419333b796123"));
+        assertEquals(2, contractCreations.size());
+
+        ContractCreation contractCreation1 = ContractCreation.builder()
+                .withContractAddress("0xbb9bc244d798123fde783fcc1c72d3bb8c189413")
+                .withContractCreator("0x793ea9692ada1900fbd0b80fffec6e431fe8b391")
+                .withTxHash("0xe9ebfecc2fa10100db51a4408d18193b3ac504584b51a4e55bdef1318f0a30f9")
+                .build();
+
+        ContractCreation contractCreation2 = ContractCreation.builder()
+                .withContractAddress("0x5eac95ad5b287cf44e058dcf694419333b796123")
+                .withContractCreator("0x7c675b7450e878e5af8550b41df42d134674e61f")
+                .withTxHash("0x79cdfec19e5a86d9022680a4d1c86d3d8cd76c21c01903a2f02c127a0a7dbfb3")
+                .build();
+
+        assertTrue(contractCreations.contains(contractCreation1));
+        assertTrue(contractCreations.contains(contractCreation2));
+    }
+
+    @Test
+    void contractCreationInvalidParamWithError() {
+        assertThrows(EtherScanInvalidAddressException.class,
+                () -> getApi().contract().contractCreation(Collections.singletonList("0xBBbc244D798123fDe783fCc1C72d3Bb8C189414")));
+    }
 }

From 234cce4cadb71e1dfd45969a7709b45533d2656f Mon Sep 17 00:00:00 2001
From: Blackmorse <blackmorse@live.com>
Date: Fri, 29 Sep 2023 12:51:00 +0400
Subject: [PATCH 51/67] Formatting

---
 .../api/etherscan/AccountAPIProvider.java          |  3 ++-
 .../io/goodforgod/api/etherscan/ContractAPI.java   |  4 ++--
 .../api/etherscan/ContractAPIProvider.java         | 10 +++++-----
 .../io/goodforgod/api/etherscan/StatisticAPI.java  |  3 +++
 .../api/etherscan/model/ContractCreation.java      | 11 ++++++++---
 .../model/response/ContractCreationResponseTO.java |  3 +--
 .../api/etherscan/contract/ContractApiTests.java   | 14 +++++++-------
 7 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index d36baf7..f968c1d 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -95,7 +95,8 @@ public List<Balance> balances(@NotNull List<String> addresses) throws EtherScanE
         final List<List<String>> addressesAsBatches = BasicUtils.partition(addresses, 20);
 
         for (final List<String> batch : addressesAsBatches) {
-            final String urlParams = ACT_BALANCE_MULTI_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + BasicUtils.toAddressParam(batch);
+            final String urlParams = ACT_BALANCE_MULTI_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM
+                    + BasicUtils.toAddressParam(batch);
             final BalanceResponseTO response = getRequest(urlParams, BalanceResponseTO.class);
             if (response.getStatus() != 1) {
                 throw new EtherScanResponseException(response);
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
index 45ecb1e..c076b74 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPI.java
@@ -3,9 +3,8 @@
 import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.model.Abi;
 import io.goodforgod.api.etherscan.model.ContractCreation;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.List;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * EtherScan - API Descriptions <a href="https://docs.etherscan.io/api-endpoints/contracts">...</a>
@@ -27,6 +26,7 @@ public interface ContractAPI {
 
     /**
      * Returns a contract's deployer address and transaction hash it was created, up to 5 at a time.
+     * 
      * @param contractAddresses - list of addresses to fetch
      * @throws EtherScanException parent exception class
      */
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index fda1b0d..0493f45 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -9,10 +9,9 @@
 import io.goodforgod.api.etherscan.model.response.ContractCreationResponseTO;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import io.goodforgod.api.etherscan.util.BasicUtils;
-import org.jetbrains.annotations.NotNull;
-
 import java.util.List;
 import java.util.stream.Collectors;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Contract API Implementation
@@ -60,7 +59,8 @@ public Abi contractAbi(@NotNull String address) throws EtherScanException {
     @Override
     public List<ContractCreation> contractCreation(@NotNull List<String> contractAddresses) throws EtherScanException {
         BasicUtils.validateAddresses(contractAddresses);
-        final String urlParam = ACT_CONTRACT_CREATION + ACT_CONTRACT_ADDRESSES_PARAM + BasicUtils.toAddressParam(contractAddresses);
+        final String urlParam = ACT_CONTRACT_CREATION + ACT_CONTRACT_ADDRESSES_PARAM
+                + BasicUtils.toAddressParam(contractAddresses);
         final ContractCreationResponseTO response = getRequest(urlParam, ContractCreationResponseTO.class);
         if (response.getStatus() != 1 && response.getMessage().startsWith("NOTOK")) {
             throw new EtherScanResponseException(response);
@@ -71,7 +71,7 @@ public List<ContractCreation> contractCreation(@NotNull List<String> contractAdd
                         .withContractCreator(to.getContractCreator())
                         .withContractAddress(to.getContractAddress())
                         .withTxHash(to.getTxHash())
-                        .build()
-                ).collect(Collectors.toList());
+                        .build())
+                .collect(Collectors.toList());
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
index d7b48b8..b6db82e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
@@ -15,6 +15,9 @@
 public interface StatisticAPI {
 
     /**
+     * ERC20 token total Supply
+     * <a href=
+     * "https://docs.etherscan.io/api-endpoints/tokens#get-erc20-token-totalsupply-by-contractaddress">EtherScan<a>
      * Returns the current amount of an ERC-20 token in circulation.
      *
      * @param contract contract address
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
index 747aefb..0f3d822 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
@@ -3,6 +3,7 @@
 import java.util.Objects;
 
 public class ContractCreation {
+
     private final String contractAddress;
     private final String contractCreator;
     private final String txHash;
@@ -27,10 +28,13 @@ public String getTxHash() {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
         ContractCreation that = (ContractCreation) o;
-        return Objects.equals(contractAddress, that.contractAddress) && Objects.equals(contractCreator, that.contractCreator) && Objects.equals(txHash, that.txHash);
+        return Objects.equals(contractAddress, that.contractAddress) && Objects.equals(contractCreator, that.contractCreator)
+                && Objects.equals(txHash, that.txHash);
     }
 
     @Override
@@ -52,6 +56,7 @@ public static ContractCreationBuilder builder() {
     }
 
     public static final class ContractCreationBuilder {
+
         private String contractAddress;
         private String contractCreator;
         private String txHash;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java
index 7cf28fc..e3766c3 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/ContractCreationResponseTO.java
@@ -1,4 +1,3 @@
 package io.goodforgod.api.etherscan.model.response;
 
-public class ContractCreationResponseTO extends BaseListResponseTO<ContractCreationTO> {
-}
+public class ContractCreationResponseTO extends BaseListResponseTO<ContractCreationTO> {}
diff --git a/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
index 49e8f07..d1e4de4 100644
--- a/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/contract/ContractApiTests.java
@@ -4,11 +4,10 @@
 import io.goodforgod.api.etherscan.error.EtherScanInvalidAddressException;
 import io.goodforgod.api.etherscan.model.Abi;
 import io.goodforgod.api.etherscan.model.ContractCreation;
-import org.junit.jupiter.api.Test;
-
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import org.junit.jupiter.api.Test;
 
 /**
  * @author GoodforGod
@@ -45,8 +44,8 @@ void correctParamWithEmptyExpectedResult() {
 
     @Test
     void correctContractCreation() {
-        List<ContractCreation> contractCreations =
-                getApi().contract().contractCreation(Collections.singletonList("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413"));
+        List<ContractCreation> contractCreations = getApi().contract()
+                .contractCreation(Collections.singletonList("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413"));
 
         assertEquals(1, contractCreations.size());
         ContractCreation contractCreation = contractCreations.get(0);
@@ -58,8 +57,8 @@ void correctContractCreation() {
 
     @Test
     void correctMultipleContractCreation() {
-        List<ContractCreation> contractCreations =
-                getApi().contract().contractCreation(Arrays.asList("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413", "0x5EaC95ad5b287cF44E058dCf694419333b796123"));
+        List<ContractCreation> contractCreations = getApi().contract().contractCreation(
+                Arrays.asList("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413", "0x5EaC95ad5b287cF44E058dCf694419333b796123"));
         assertEquals(2, contractCreations.size());
 
         ContractCreation contractCreation1 = ContractCreation.builder()
@@ -81,6 +80,7 @@ void correctMultipleContractCreation() {
     @Test
     void contractCreationInvalidParamWithError() {
         assertThrows(EtherScanInvalidAddressException.class,
-                () -> getApi().contract().contractCreation(Collections.singletonList("0xBBbc244D798123fDe783fCc1C72d3Bb8C189414")));
+                () -> getApi().contract()
+                        .contractCreation(Collections.singletonList("0xBBbc244D798123fDe783fCc1C72d3Bb8C189414")));
     }
 }

From 64540b8499b4cfdc284d04db01ecadbbc1a1e360 Mon Sep 17 00:00:00 2001
From: Blackmorse <blackmorse@live.com>
Date: Sun, 1 Oct 2023 16:59:32 +0400
Subject: [PATCH 52/67] filtering out empty env

---
 src/test/java/io/goodforgod/api/etherscan/ApiRunner.java | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index 4b52c00..fd933c2 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -2,6 +2,8 @@
 
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import java.util.Map;
+
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 
@@ -15,6 +17,7 @@ public class ApiRunner extends Assertions {
     static {
         API_KEY = System.getenv().entrySet().stream()
                 .filter(e -> e.getKey().startsWith("ETHERSCAN_API_KEY"))
+                .filter(e -> !BasicUtils.isBlank(e.getValue()))
                 .map(Map.Entry::getValue)
                 .findFirst()
                 .orElse(DEFAULT_KEY);

From 06464f87498713c03ab27b5232586057bd066138 Mon Sep 17 00:00:00 2001
From: Blackmorse <blackmorse@live.com>
Date: Thu, 5 Oct 2023 00:58:32 +0400
Subject: [PATCH 53/67] Fix codestyle

---
 src/test/java/io/goodforgod/api/etherscan/ApiRunner.java | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index fd933c2..a6c43ac 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -1,9 +1,8 @@
 package io.goodforgod.api.etherscan;
 
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
-import java.util.Map;
-
 import io.goodforgod.api.etherscan.util.BasicUtils;
+import java.util.Map;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 

From 3a87ca83cda95a61415bc5226651b5d18448900f Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Fri, 6 Oct 2023 02:10:05 +0300
Subject: [PATCH 54/67] [2.1.0-SNAPSHOT]
 EtherScanAPI.Builder#withRetryOnLimitReach added

---
 gradle.properties                             |  2 +-
 .../api/etherscan/AccountAPIProvider.java     |  5 +-
 .../api/etherscan/BasicProvider.java          | 51 ++++++++++++++++---
 .../api/etherscan/BlockAPIProvider.java       | 12 ++---
 .../api/etherscan/ContractAPIProvider.java    |  5 +-
 .../api/etherscan/EthScanAPIBuilder.java      | 13 ++++-
 .../api/etherscan/EtherScanAPI.java           | 11 ++++
 .../api/etherscan/EtherScanAPIProvider.java   | 19 +++----
 .../api/etherscan/GasTrackerAPIProvider.java  |  5 +-
 .../api/etherscan/LogsAPIProvider.java        |  5 +-
 .../api/etherscan/ProxyAPIProvider.java       |  5 +-
 .../api/etherscan/StatisticAPIProvider.java   |  5 +-
 .../api/etherscan/TransactionAPIProvider.java |  5 +-
 .../manager/RequestQueueManager.java          | 10 ++--
 .../goodforgod/api/etherscan/model/Abi.java   |  2 +-
 .../api/etherscan/model/Balance.java          |  2 +-
 .../goodforgod/api/etherscan/model/Block.java |  2 +-
 .../api/etherscan/model/BlockUncle.java       |  8 +--
 .../api/etherscan/model/ContractCreation.java | 29 ++++++-----
 .../api/etherscan/model/EthSupply.java        |  8 +--
 .../goodforgod/api/etherscan/model/Log.java   | 18 +++----
 .../goodforgod/api/etherscan/model/Price.java |  4 +-
 .../api/etherscan/model/Status.java           |  2 +-
 .../api/etherscan/model/TokenBalance.java     |  2 +-
 .../io/goodforgod/api/etherscan/model/Tx.java | 18 +++----
 .../api/etherscan/model/TxErc1155.java        | 22 ++++----
 .../api/etherscan/model/TxErc20.java          | 20 ++++----
 .../api/etherscan/model/TxErc721.java         | 22 ++++----
 .../api/etherscan/model/TxInternal.java       | 18 +++----
 .../api/etherscan/model/proxy/BlockProxy.java | 36 ++++++-------
 .../etherscan/model/proxy/ReceiptProxy.java   | 22 ++++----
 .../api/etherscan/model/proxy/TxProxy.java    | 28 +++++-----
 .../goodforgod/api/etherscan/ApiRunner.java   |  1 +
 33 files changed, 242 insertions(+), 175 deletions(-)

diff --git a/gradle.properties b/gradle.properties
index 821da06..ee5fd3b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,6 @@
 groupId=com.github.goodforgod
 artifactId=java-etherscan-api
-artifactVersion=2.0.0
+artifactVersion=2.1.0-SNAPSHOT
 
 
 ##### GRADLE #####
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index f968c1d..750d525 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -50,8 +50,9 @@ final class AccountAPIProvider extends BasicProvider implements AccountAPI {
     AccountAPIProvider(RequestQueueManager requestQueueManager,
                        String baseUrl,
                        EthHttpClient executor,
-                       Converter converter) {
-        super(requestQueueManager, "account", baseUrl, executor, converter);
+                       Converter converter,
+                       int retryCount) {
+        super(requestQueueManager, "account", baseUrl, executor, converter, retryCount);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 5c61aad..41abd16 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -30,20 +30,23 @@ abstract class BasicProvider {
     private final EthHttpClient executor;
     private final RequestQueueManager queue;
     private final Converter converter;
+    private final int retryCountLimit;
 
     BasicProvider(RequestQueueManager requestQueueManager,
                   String module,
                   String baseUrl,
                   EthHttpClient ethHttpClient,
-                  Converter converter) {
+                  Converter converter,
+                  int retryCountLimit) {
         this.queue = requestQueueManager;
         this.module = "&module=" + module;
         this.baseUrl = baseUrl;
         this.executor = ethHttpClient;
         this.converter = converter;
+        this.retryCountLimit = retryCountLimit;
     }
 
-    <T> T convert(byte[] json, Class<T> tClass) {
+    private <T> T convert(byte[] json, Class<T> tClass) {
         try {
             final T t = converter.fromJson(json, tClass);
             if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith(MAX_RATE_LIMIT_REACHED)) {
@@ -66,23 +69,59 @@ <T> T convert(byte[] json, Class<T> tClass) {
         }
     }
 
-    byte[] getRequest(String urlParameters) {
+    private byte[] getRequest(String urlParameters) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
         return executor.get(uri);
     }
 
-    byte[] postRequest(String urlParameters, String dataToPost) {
+    private byte[] postRequest(String urlParameters, String dataToPost) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
         return executor.post(uri, dataToPost.getBytes(StandardCharsets.UTF_8));
     }
 
     <T> T getRequest(String urlParameters, Class<T> tClass) {
-        return convert(getRequest(urlParameters), tClass);
+        return getRequest(urlParameters, tClass, 0);
+    }
+
+    private <T> T getRequest(String urlParameters, Class<T> tClass, int retryCount) {
+        try {
+            return convert(getRequest(urlParameters), tClass);
+        } catch (Exception e) {
+            if (retryCount < retryCountLimit) {
+                try {
+                    Thread.sleep(1150);
+                } catch (InterruptedException ex) {
+                    throw new IllegalStateException(ex);
+                }
+
+                return getRequest(urlParameters, tClass, retryCount + 1);
+            } else {
+                throw e;
+            }
+        }
     }
 
     <T> T postRequest(String urlParameters, String dataToPost, Class<T> tClass) {
-        return convert(postRequest(urlParameters, dataToPost), tClass);
+        return postRequest(urlParameters, dataToPost, tClass, 0);
+    }
+
+    private <T> T postRequest(String urlParameters, String dataToPost, Class<T> tClass, int retryCount) {
+        try {
+            return convert(postRequest(urlParameters, dataToPost), tClass);
+        } catch (EtherScanRateLimitException e) {
+            if (retryCount < retryCountLimit) {
+                try {
+                    Thread.sleep(1150);
+                } catch (InterruptedException ex) {
+                    throw new IllegalStateException(ex);
+                }
+
+                return postRequest(urlParameters, dataToPost, tClass, retryCount + 1);
+            } else {
+                throw e;
+            }
+        }
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
index 406ac19..b3604a7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
@@ -26,21 +26,17 @@ final class BlockAPIProvider extends BasicProvider implements BlockAPI {
     BlockAPIProvider(RequestQueueManager requestQueueManager,
                      String baseUrl,
                      EthHttpClient executor,
-                     Converter converter) {
-        super(requestQueueManager, "block", baseUrl, executor, converter);
+                     Converter converter,
+                     int retryCount) {
+        super(requestQueueManager, "block", baseUrl, executor, converter, retryCount);
     }
 
     @NotNull
     @Override
     public Optional<BlockUncle> uncles(long blockNumber) throws EtherScanException {
         final String urlParam = ACT_BLOCK_PARAM + BLOCKNO_PARAM + blockNumber;
-        final byte[] response = getRequest(urlParam);
-        if (response.length == 0) {
-            return Optional.empty();
-        }
-
         try {
-            final UncleBlockResponseTO responseTO = convert(response, UncleBlockResponseTO.class);
+            final UncleBlockResponseTO responseTO = getRequest(urlParam, UncleBlockResponseTO.class);
             if (responseTO.getMessage().startsWith("NOTOK")) {
                 return Optional.empty();
             }
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index 0493f45..898a7b7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -35,8 +35,9 @@ final class ContractAPIProvider extends BasicProvider implements ContractAPI {
     ContractAPIProvider(RequestQueueManager requestQueueManager,
                         String baseUrl,
                         EthHttpClient executor,
-                        Converter converter) {
-        super(requestQueueManager, "contract", baseUrl, executor, converter);
+                        Converter converter,
+                        int retryCount) {
+        super(requestQueueManager, "contract", baseUrl, executor, converter, retryCount);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index dad9c50..70d9a01 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -26,6 +26,7 @@ final class EthScanAPIBuilder implements EtherScanAPI.Builder {
 
     private final Gson gson = new GsonConfiguration().builder().create();
 
+    private int retryCountOnLimitReach = 0;
     private String apiKey = DEFAULT_KEY;
     private RequestQueueManager queueManager;
     private EthNetwork ethNetwork = EthNetworks.MAINNET;
@@ -87,6 +88,16 @@ public EtherScanAPI.Builder withConverter(@NotNull Supplier<Converter> converter
         return this;
     }
 
+    @NotNull
+    public EtherScanAPI.Builder withRetryOnLimitReach(int maxRetryCount) {
+        if (maxRetryCount < 0 || maxRetryCount > 20) {
+            throw new IllegalStateException("maxRetryCount value must be in range from 0 to 20, but was: " + maxRetryCount);
+        }
+
+        this.retryCountOnLimitReach = maxRetryCount;
+        return this;
+    }
+
     @Override
     public @NotNull EtherScanAPI build() {
         RequestQueueManager requestQueueManager;
@@ -99,6 +110,6 @@ public EtherScanAPI.Builder withConverter(@NotNull Supplier<Converter> converter
         }
 
         return new EtherScanAPIProvider(apiKey, ethNetwork, requestQueueManager, ethHttpClientSupplier.get(),
-                converterSupplier.get());
+                converterSupplier.get(), retryCountOnLimitReach);
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
index 6da3d8f..4e6bc57 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -1,9 +1,11 @@
 package io.goodforgod.api.etherscan;
 
+import io.goodforgod.api.etherscan.error.EtherScanRateLimitException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import java.util.function.Supplier;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Range;
 
 /**
  * EtherScan full API Description <a href="https://etherscan.io/apis">...</a>
@@ -62,6 +64,15 @@ interface Builder {
         @NotNull
         Builder withConverter(@NotNull Supplier<Converter> converterSupplier);
 
+        /**
+         * By default is disabled
+         *
+         * @param maxRetryCount to retry if {@link EtherScanRateLimitException} thrown
+         * @return self
+         */
+        @NotNull
+        EtherScanAPI.Builder withRetryOnLimitReach(@Range(from = 0, to = 20) int maxRetryCount);
+
         @NotNull
         EtherScanAPI build();
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
index e698f45..ab6e863 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
@@ -26,19 +26,20 @@ final class EtherScanAPIProvider implements EtherScanAPI {
                          EthNetwork network,
                          RequestQueueManager queue,
                          EthHttpClient ethHttpClient,
-                         Converter converter) {
+                         Converter converter,
+                         int retryCount) {
         // EtherScan 1request\5sec limit support by queue manager
         final String baseUrl = network.domain() + "?apikey=" + apiKey;
 
         this.requestQueueManager = queue;
-        this.account = new AccountAPIProvider(queue, baseUrl, ethHttpClient, converter);
-        this.block = new BlockAPIProvider(queue, baseUrl, ethHttpClient, converter);
-        this.contract = new ContractAPIProvider(queue, baseUrl, ethHttpClient, converter);
-        this.logs = new LogsAPIProvider(queue, baseUrl, ethHttpClient, converter);
-        this.proxy = new ProxyAPIProvider(queue, baseUrl, ethHttpClient, converter);
-        this.stats = new StatisticAPIProvider(queue, baseUrl, ethHttpClient, converter);
-        this.txs = new TransactionAPIProvider(queue, baseUrl, ethHttpClient, converter);
-        this.gasTracker = new GasTrackerAPIProvider(queue, baseUrl, ethHttpClient, converter);
+        this.account = new AccountAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
+        this.block = new BlockAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
+        this.contract = new ContractAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
+        this.logs = new LogsAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
+        this.proxy = new ProxyAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
+        this.stats = new StatisticAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
+        this.txs = new TransactionAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
+        this.gasTracker = new GasTrackerAPIProvider(queue, baseUrl, ethHttpClient, converter, retryCount);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
index cbe0a75..ed717a9 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
@@ -28,8 +28,9 @@ final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI
     GasTrackerAPIProvider(RequestQueueManager queue,
                           String baseUrl,
                           EthHttpClient ethHttpClient,
-                          Converter converter) {
-        super(queue, "gastracker", baseUrl, ethHttpClient, converter);
+                          Converter converter,
+                          int retryCount) {
+        super(queue, "gastracker", baseUrl, ethHttpClient, converter, retryCount);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
index d294fb5..237cafd 100644
--- a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
@@ -25,8 +25,9 @@ final class LogsAPIProvider extends BasicProvider implements LogsAPI {
     LogsAPIProvider(RequestQueueManager queue,
                     String baseUrl,
                     EthHttpClient executor,
-                    Converter converter) {
-        super(queue, "logs", baseUrl, executor, converter);
+                    Converter converter,
+                    int retryCount) {
+        super(queue, "logs", baseUrl, executor, converter, retryCount);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index 4dff589..428b48f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -60,8 +60,9 @@ final class ProxyAPIProvider extends BasicProvider implements ProxyAPI {
     ProxyAPIProvider(RequestQueueManager queue,
                      String baseUrl,
                      EthHttpClient executor,
-                     Converter converter) {
-        super(queue, "proxy", baseUrl, executor, converter);
+                     Converter converter,
+                     int retryCount) {
+        super(queue, "proxy", baseUrl, executor, converter, retryCount);
     }
 
     @Override
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
index 131df71..a2bba16 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
@@ -33,8 +33,9 @@ final class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
     StatisticAPIProvider(RequestQueueManager queue,
                          String baseUrl,
                          EthHttpClient executor,
-                         Converter converter) {
-        super(queue, "stats", baseUrl, executor, converter);
+                         Converter converter,
+                         int retry) {
+        super(queue, "stats", baseUrl, executor, converter, retry);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
index da26b51..7374335 100644
--- a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
@@ -27,8 +27,9 @@ final class TransactionAPIProvider extends BasicProvider implements TransactionA
     TransactionAPIProvider(RequestQueueManager queue,
                            String baseUrl,
                            EthHttpClient executor,
-                           Converter converter) {
-        super(queue, "transaction", baseUrl, executor, converter);
+                           Converter converter,
+                           int retryCount) {
+        super(queue, "transaction", baseUrl, executor, converter, retryCount);
     }
 
     @NotNull
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
index 0f36b23..92875d0 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/RequestQueueManager.java
@@ -17,7 +17,7 @@ public interface RequestQueueManager extends AutoCloseable {
      * Is used by default when no API KEY is provided
      */
     static RequestQueueManager anonymous() {
-        return new SemaphoreRequestQueueManager(1, Duration.ofMillis(5015L));
+        return new SemaphoreRequestQueueManager(1, Duration.ofMillis(5045L));
     }
 
     /**
@@ -25,19 +25,19 @@ static RequestQueueManager anonymous() {
      * <a href="https://docs.etherscan.io/getting-started/viewing-api-usage-statistics">Free API KEY</a>
      */
     static RequestQueueManager planFree() {
-        return new SemaphoreRequestQueueManager(5, Duration.ofMillis(1015L));
+        return new SemaphoreRequestQueueManager(5, Duration.ofMillis(1045L));
     }
 
     static RequestQueueManager planStandard() {
-        return new SemaphoreRequestQueueManager(10, Duration.ofMillis(1015L));
+        return new SemaphoreRequestQueueManager(10, Duration.ofMillis(1045L));
     }
 
     static RequestQueueManager planAdvanced() {
-        return new SemaphoreRequestQueueManager(20, Duration.ofMillis(1015L));
+        return new SemaphoreRequestQueueManager(20, Duration.ofMillis(1045L));
     }
 
     static RequestQueueManager planProfessional() {
-        return new SemaphoreRequestQueueManager(30, Duration.ofMillis(1015L));
+        return new SemaphoreRequestQueueManager(30, Duration.ofMillis(1045L));
     }
 
     static RequestQueueManager unlimited() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
index 3536bf9..fbf71be 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
@@ -55,7 +55,7 @@ public int hashCode() {
     @Override
     public String toString() {
         return "Abi{" +
-                "contractAbi='" + contractAbi + '\'' +
+                "contractAbi=" + contractAbi +
                 ", isVerified=" + isVerified +
                 '}';
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
index 079d4b6..1d2f743 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Balance.java
@@ -45,7 +45,7 @@ public int hashCode() {
     @Override
     public String toString() {
         return "Balance{" +
-                "address='" + address + '\'' +
+                "address=" + address +
                 ", balance=" + balance +
                 '}';
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Block.java b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
index 0550000..da1184b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Block.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Block.java
@@ -58,7 +58,7 @@ public String toString() {
         return "Block{" +
                 "blockNumber=" + blockNumber +
                 ", blockReward=" + blockReward +
-                ", timeStamp='" + timeStamp + '\'' +
+                ", timeStamp=" + timeStamp +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
index 9b110d9..961db7e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
@@ -19,7 +19,7 @@ public static class Uncle {
         private BigInteger blockreward;
         private int unclePosition;
 
-        private Uncle() {}
+        protected Uncle() {}
 
         // <editor-fold desc="Getters">
         public String getMiner() {
@@ -54,7 +54,7 @@ public int hashCode() {
         @Override
         public String toString() {
             return "Uncle{" +
-                    "miner='" + miner + '\'' +
+                    "miner=" + miner +
                     ", blockreward=" + blockreward +
                     ", unclePosition=" + unclePosition +
                     '}';
@@ -128,9 +128,9 @@ public String getUncleInclusionReward() {
     @Override
     public String toString() {
         return "UncleBlock{" +
-                "blockMiner='" + blockMiner + '\'' +
+                "blockMiner=" + blockMiner +
                 ", uncles=" + uncles +
-                ", uncleInclusionReward='" + uncleInclusionReward + '\'' +
+                ", uncleInclusionReward=" + uncleInclusionReward +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
index 0f3d822..2082883 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
@@ -4,15 +4,11 @@
 
 public class ContractCreation {
 
-    private final String contractAddress;
-    private final String contractCreator;
-    private final String txHash;
-
-    private ContractCreation(String contractAddress, String contractCreator, String txHash) {
-        this.contractAddress = contractAddress;
-        this.contractCreator = contractCreator;
-        this.txHash = txHash;
-    }
+    private String contractAddress;
+    private String contractCreator;
+    private String txHash;
+
+    protected ContractCreation() {}
 
     public String getContractAddress() {
         return contractAddress;
@@ -33,7 +29,8 @@ public boolean equals(Object o) {
         if (o == null || getClass() != o.getClass())
             return false;
         ContractCreation that = (ContractCreation) o;
-        return Objects.equals(contractAddress, that.contractAddress) && Objects.equals(contractCreator, that.contractCreator)
+        return Objects.equals(contractAddress, that.contractAddress)
+                && Objects.equals(contractCreator, that.contractCreator)
                 && Objects.equals(txHash, that.txHash);
     }
 
@@ -45,9 +42,9 @@ public int hashCode() {
     @Override
     public String toString() {
         return "ContractCreation{" +
-                "contractAddress='" + contractAddress + '\'' +
-                ", contractCreator='" + contractCreator + '\'' +
-                ", txHash='" + txHash + '\'' +
+                "contractAddress=" + contractAddress +
+                ", contractCreator=" + contractCreator +
+                ", txHash=" + txHash +
                 '}';
     }
 
@@ -79,7 +76,11 @@ public ContractCreationBuilder withTxHash(String txHash) {
         }
 
         public ContractCreation build() {
-            return new ContractCreation(contractAddress, contractCreator, txHash);
+            ContractCreation contractCreation = new ContractCreation();
+            contractCreation.contractAddress = contractAddress;
+            contractCreation.contractCreator = contractCreator;
+            contractCreation.txHash = txHash;
+            return contractCreation;
         }
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
index 344e754..c626069 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
@@ -56,10 +56,10 @@ public int hashCode() {
     @Override
     public String toString() {
         return "EthSupply{" +
-                "EthSupply='" + EthSupply + '\'' +
-                ", Eth2Staking='" + Eth2Staking + '\'' +
-                ", BurntFees='" + BurntFees + '\'' +
-                ", WithdrawnTotal='" + WithdrawnTotal + '\'' +
+                "EthSupply=" + EthSupply +
+                ", Eth2Staking=" + Eth2Staking +
+                ", BurntFees=" + BurntFees +
+                ", WithdrawnTotal=" + WithdrawnTotal +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index da6c295..d54766c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -138,16 +138,16 @@ public int hashCode() {
     @Override
     public String toString() {
         return "Log{" +
-                "blockNumber='" + blockNumber + '\'' +
-                ", address='" + address + '\'' +
-                ", transactionHash='" + transactionHash + '\'' +
-                ", transactionIndex='" + transactionIndex + '\'' +
-                ", timeStamp='" + timeStamp + '\'' +
-                ", data='" + data + '\'' +
-                ", gasPrice='" + gasPrice + '\'' +
-                ", gasUsed='" + gasUsed + '\'' +
+                "blockNumber=" + blockNumber +
+                ", address=" + address +
+                ", transactionHash=" + transactionHash +
+                ", transactionIndex=" + transactionIndex +
+                ", timeStamp=" + timeStamp +
+                ", data=" + data +
+                ", gasPrice=" + gasPrice +
+                ", gasUsed=" + gasUsed +
                 ", topics=" + topics +
-                ", logIndex='" + logIndex + '\'' +
+                ", logIndex=" + logIndex +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
index 565dbed..403b705 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -67,8 +67,8 @@ public String toString() {
         return "Price{" +
                 "ethusd=" + ethusd +
                 ", ethbtc=" + ethbtc +
-                ", ethusd_timestamp='" + ethusd_timestamp + '\'' +
-                ", ethbtc_timestamp='" + ethbtc_timestamp + '\'' +
+                ", ethusd_timestamp=" + ethusd_timestamp +
+                ", ethbtc_timestamp=" + ethbtc_timestamp +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Status.java b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
index 052c187..41b598a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Status.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
@@ -45,7 +45,7 @@ public int hashCode() {
     public String toString() {
         return "Status{" +
                 "isError=" + isError +
-                ", errDescription='" + errDescription + '\'' +
+                ", errDescription=" + errDescription +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
index bb40ee2..c257654 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TokenBalance.java
@@ -39,7 +39,7 @@ public int hashCode() {
     @Override
     public String toString() {
         return "TokenBalance{" +
-                "tokenContract='" + tokenContract + '\'' +
+                "tokenContract=" + tokenContract +
                 '}';
     }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 7ef0e22..0a836d1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -35,21 +35,21 @@ public String getTxReceiptStatus() {
     public String toString() {
         return "Tx{" +
                 "value=" + value +
-                ", isError='" + isError + '\'' +
-                ", txreceipt_status='" + txreceipt_status + '\'' +
+                ", isError=" + isError +
+                ", txreceipt_status=" + txreceipt_status +
                 ", nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
+                ", blockHash=" + blockHash +
                 ", transactionIndex=" + transactionIndex +
                 ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
                 ", blockNumber=" + blockNumber +
-                ", timeStamp='" + timeStamp + '\'' +
-                ", hash='" + hash + '\'' +
-                ", from='" + from + '\'' +
-                ", to='" + to + '\'' +
-                ", contractAddress='" + contractAddress + '\'' +
-                ", input='" + input + '\'' +
+                ", timeStamp=" + timeStamp +
+                ", hash=" + hash +
+                ", from=" + from +
+                ", to=" + to +
+                ", contractAddress=" + contractAddress +
+                ", input=" + input +
                 ", gas=" + gas +
                 ", gasUsed=" + gasUsed +
                 '}';
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
index 16d4457..f0b1ce4 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -56,23 +56,23 @@ public int hashCode() {
     @Override
     public String toString() {
         return "TxErc1155{" +
-                "tokenID='" + tokenID + '\'' +
-                ", tokenName='" + tokenName + '\'' +
-                ", tokenSymbol='" + tokenSymbol + '\'' +
-                ", tokenValue='" + tokenValue + '\'' +
+                "tokenID=" + tokenID +
+                ", tokenName=" + tokenName +
+                ", tokenSymbol=" + tokenSymbol +
+                ", tokenValue=" + tokenValue +
                 ", nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
+                ", blockHash=" + blockHash +
                 ", transactionIndex=" + transactionIndex +
                 ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
                 ", blockNumber=" + blockNumber +
-                ", timeStamp='" + timeStamp + '\'' +
-                ", hash='" + hash + '\'' +
-                ", from='" + from + '\'' +
-                ", to='" + to + '\'' +
-                ", contractAddress='" + contractAddress + '\'' +
-                ", input='" + input + '\'' +
+                ", timeStamp=" + timeStamp +
+                ", hash=" + hash +
+                ", from=" + from +
+                ", to=" + to +
+                ", contractAddress=" + contractAddress +
+                ", input=" + input +
                 ", gas=" + gas +
                 ", gasUsed=" + gasUsed +
                 '}';
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index 3dc22fd..1d6080e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -58,22 +58,22 @@ public int hashCode() {
     public String toString() {
         return "TxErc20{" +
                 "value=" + value +
-                ", tokenName='" + tokenName + '\'' +
-                ", tokenSymbol='" + tokenSymbol + '\'' +
-                ", tokenDecimal='" + tokenDecimal + '\'' +
+                ", tokenName=" + tokenName +
+                ", tokenSymbol=" + tokenSymbol +
+                ", tokenDecimal=" + tokenDecimal +
                 ", nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
+                ", blockHash=" + blockHash +
                 ", transactionIndex=" + transactionIndex +
                 ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
                 ", blockNumber=" + blockNumber +
-                ", timeStamp='" + timeStamp + '\'' +
-                ", hash='" + hash + '\'' +
-                ", from='" + from + '\'' +
-                ", to='" + to + '\'' +
-                ", contractAddress='" + contractAddress + '\'' +
-                ", input='" + input + '\'' +
+                ", timeStamp=" + timeStamp +
+                ", hash=" + hash +
+                ", from=" + from +
+                ", to=" + to +
+                ", contractAddress=" + contractAddress +
+                ", input=" + input +
                 ", gas=" + gas +
                 ", gasUsed=" + gasUsed +
                 '}';
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 2180019..1ac49a0 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -56,23 +56,23 @@ public int hashCode() {
     @Override
     public String toString() {
         return "TxErc721{" +
-                "tokenID='" + tokenID + '\'' +
-                ", tokenName='" + tokenName + '\'' +
-                ", tokenSymbol='" + tokenSymbol + '\'' +
-                ", tokenDecimal='" + tokenDecimal + '\'' +
+                "tokenID=" + tokenID +
+                ", tokenName=" + tokenName +
+                ", tokenSymbol=" + tokenSymbol +
+                ", tokenDecimal=" + tokenDecimal +
                 ", nonce=" + nonce +
-                ", blockHash='" + blockHash + '\'' +
+                ", blockHash=" + blockHash +
                 ", transactionIndex=" + transactionIndex +
                 ", confirmations=" + confirmations +
                 ", gasPrice=" + gasPrice +
                 ", cumulativeGasUsed=" + cumulativeGasUsed +
                 ", blockNumber=" + blockNumber +
-                ", timeStamp='" + timeStamp + '\'' +
-                ", hash='" + hash + '\'' +
-                ", from='" + from + '\'' +
-                ", to='" + to + '\'' +
-                ", contractAddress='" + contractAddress + '\'' +
-                ", input='" + input + '\'' +
+                ", timeStamp=" + timeStamp +
+                ", hash=" + hash +
+                ", from=" + from +
+                ", to=" + to +
+                ", contractAddress=" + contractAddress +
+                ", input=" + input +
                 ", gas=" + gas +
                 ", gasUsed=" + gasUsed +
                 '}';
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index a61cf83..389f456 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -69,17 +69,17 @@ public int hashCode() {
     public String toString() {
         return "TxInternal{" +
                 "value=" + value +
-                ", type='" + type + '\'' +
-                ", traceId='" + traceId + '\'' +
+                ", type=" + type +
+                ", traceId=" + traceId +
                 ", isError=" + isError +
-                ", errCode='" + errCode + '\'' +
+                ", errCode=" + errCode +
                 ", blockNumber=" + blockNumber +
-                ", timeStamp='" + timeStamp + '\'' +
-                ", hash='" + hash + '\'' +
-                ", from='" + from + '\'' +
-                ", to='" + to + '\'' +
-                ", contractAddress='" + contractAddress + '\'' +
-                ", input='" + input + '\'' +
+                ", timeStamp=" + timeStamp +
+                ", hash=" + hash +
+                ", from=" + from +
+                ", to=" + to +
+                ", contractAddress=" + contractAddress +
+                ", input=" + input +
                 ", gas=" + gas +
                 ", gasUsed=" + gasUsed +
                 '}';
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index 4a2b624..bee4d64 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -162,25 +162,25 @@ public int hashCode() {
     @Override
     public String toString() {
         return "BlockProxy{" +
-                "number='" + number + '\'' +
-                ", hash='" + hash + '\'' +
-                ", parentHash='" + parentHash + '\'' +
-                ", stateRoot='" + stateRoot + '\'' +
-                ", size='" + size + '\'' +
-                ", difficulty='" + difficulty + '\'' +
-                ", totalDifficulty='" + totalDifficulty + '\'' +
-                ", timestamp='" + timestamp + '\'' +
-                ", miner='" + miner + '\'' +
-                ", nonce='" + nonce + '\'' +
-                ", extraData='" + extraData + '\'' +
-                ", logsBloom='" + logsBloom + '\'' +
-                ", mixHash='" + mixHash + '\'' +
-                ", gasUsed='" + gasUsed + '\'' +
-                ", gasLimit='" + gasLimit + '\'' +
-                ", sha3Uncles='" + sha3Uncles + '\'' +
+                "number=" + number +
+                ", hash=" + hash +
+                ", parentHash=" + parentHash +
+                ", stateRoot=" + stateRoot +
+                ", size=" + size +
+                ", difficulty=" + difficulty +
+                ", totalDifficulty=" + totalDifficulty +
+                ", timestamp=" + timestamp +
+                ", miner=" + miner +
+                ", nonce=" + nonce +
+                ", extraData=" + extraData +
+                ", logsBloom=" + logsBloom +
+                ", mixHash=" + mixHash +
+                ", gasUsed=" + gasUsed +
+                ", gasLimit=" + gasLimit +
+                ", sha3Uncles=" + sha3Uncles +
                 ", uncles=" + uncles +
-                ", receiptsRoot='" + receiptsRoot + '\'' +
-                ", transactionsRoot='" + transactionsRoot + '\'' +
+                ", receiptsRoot=" + receiptsRoot +
+                ", transactionsRoot=" + transactionsRoot +
                 ", transactions=" + transactions +
                 '}';
     }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index e6df01c..d88fd6d 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -115,18 +115,18 @@ public int hashCode() {
     @Override
     public String toString() {
         return "ReceiptProxy{" +
-                "root='" + root + '\'' +
-                ", from='" + from + '\'' +
-                ", to='" + to + '\'' +
-                ", blockNumber='" + blockNumber + '\'' +
-                ", blockHash='" + blockHash + '\'' +
-                ", transactionHash='" + transactionHash + '\'' +
-                ", transactionIndex='" + transactionIndex + '\'' +
-                ", gasUsed='" + gasUsed + '\'' +
-                ", cumulativeGasUsed='" + cumulativeGasUsed + '\'' +
-                ", contractAddress='" + contractAddress + '\'' +
+                "root=" + root +
+                ", from=" + from +
+                ", to=" + to +
+                ", blockNumber=" + blockNumber +
+                ", blockHash=" + blockHash +
+                ", transactionHash=" + transactionHash +
+                ", transactionIndex=" + transactionIndex +
+                ", gasUsed=" + gasUsed +
+                ", cumulativeGasUsed=" + cumulativeGasUsed +
+                ", contractAddress=" + contractAddress +
                 ", logs=" + logs +
-                ", logsBloom='" + logsBloom + '\'' +
+                ", logsBloom=" + logsBloom +
                 '}';
     }
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index 70b4fd7..0a89921 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -127,20 +127,20 @@ public int hashCode() {
     @Override
     public String toString() {
         return "TxProxy{" +
-                "to='" + to + '\'' +
-                ", hash='" + hash + '\'' +
-                ", transactionIndex='" + transactionIndex + '\'' +
-                ", from='" + from + '\'' +
-                ", v='" + v + '\'' +
-                ", input='" + input + '\'' +
-                ", s='" + s + '\'' +
-                ", r='" + r + '\'' +
-                ", nonce='" + nonce + '\'' +
-                ", value='" + value + '\'' +
-                ", gas='" + gas + '\'' +
-                ", gasPrice='" + gasPrice + '\'' +
-                ", blockHash='" + blockHash + '\'' +
-                ", blockNumber='" + blockNumber + '\'' +
+                "to=" + to +
+                ", hash=" + hash +
+                ", transactionIndex=" + transactionIndex +
+                ", from=" + from +
+                ", v=" + v +
+                ", input=" + input +
+                ", s=" + s +
+                ", r=" + r +
+                ", nonce=" + nonce +
+                ", value=" + value +
+                ", gas=" + gas +
+                ", gasPrice=" + gasPrice +
+                ", blockHash=" + blockHash +
+                ", blockNumber=" + blockNumber +
                 '}';
     }
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index a6c43ac..72aeeff 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -29,6 +29,7 @@ public class ApiRunner extends Assertions {
                 .withApiKey(ApiRunner.API_KEY)
                 .withNetwork(EthNetworks.MAINNET)
                 .withQueue(queueManager)
+                .withRetryOnLimitReach(5)
                 .build();
     }
 

From 3405883f524a98b8c5c5848ddd862b140cac28aa Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Fri, 6 Oct 2023 02:10:53 +0300
Subject: [PATCH 55/67] [2.1.0-SNAPSHOT] build.gradle updated for new CI
 CONTRIBUTING.md added README.md updated

---
 CONTRIBUTING.md                          |  23 +++++++++++
 README.md                                |   7 ++--
 _config.yml                              |   1 -
 build.gradle                             |  48 +++++++++++++++++++----
 gradle/wrapper/gradle-wrapper.jar        | Bin 59536 -> 61574 bytes
 gradle/wrapper/gradle-wrapper.properties |   3 +-
 gradlew                                  |  18 +++++++--
 gradlew.bat                              |  15 ++++---
 8 files changed, 92 insertions(+), 23 deletions(-)
 create mode 100644 CONTRIBUTING.md
 delete mode 100644 _config.yml

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..5abd8dc
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+# Contributing Code or Documentation Guide
+
+## Running Tests
+
+The new code should contain tests that check new behavior.
+
+Run tests `./gradlew test` to check that code works as behavior.
+
+## Code Style
+
+The code base should remain clean, following industry best practices for organization, javadoc and style, as much as possible.
+
+To run the Code Style check use `./gradlew spotlessCheck`.
+
+If check found any errors, you can apply Code Style by running `./gradlew spotlessApply`
+
+## Creating a pull request
+
+Once you are satisfied with your changes:
+
+- Commit changes to the local branch you created.
+- Push that branch with changes to the corresponding remote branch on GitHub
+- Submit a [pull request](https://help.github.com/articles/creating-a-pull-request) to `dev` branch.
\ No newline at end of file
diff --git a/README.md b/README.md
index dd244b5..c086a6b 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
 # Java EtherScan API 
 
 [![Minimum required Java version](https://img.shields.io/badge/Java-1.8%2B-blue?logo=openjdk)](https://openjdk.org/projects/jdk8/)
-[![GitHub Action](https://github.com/goodforgod/java-etherscan-api/workflows/Java%20CI/badge.svg)](https://github.com/GoodforGod/java-etherscan-api/actions?query=workflow%3A%22Java+CI%22)
+[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.goodforgod/java-etherscan-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.goodforgod/java-etherscan-api)
+[![Java CI](https://github.com/GoodforGod/java-etherscan-api/workflows/CI%20Master/badge.svg)](https://github.com/GoodforGod/java-etherscan-api/actions?query=workflow%3ACI+Master)
 [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=coverage)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
 [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
 [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=ncloc)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
@@ -14,7 +15,7 @@ Library supports EtherScan *API* for all available *Ethereum Networks* for *ethe
 
 **Gradle**
 ```groovy
-implementation "com.github.goodforgod:java-etherscan-api:2.0.0"
+implementation "com.github.goodforgod:java-etherscan-api:2.1.0"
 ```
 
 **Maven**
@@ -22,7 +23,7 @@ implementation "com.github.goodforgod:java-etherscan-api:2.0.0"
 <dependency>
     <groupId>com.github.goodforgod</groupId>
     <artifactId>java-etherscan-api</artifactId>
-    <version>2.0.0</version>
+    <version>2.1.0</version>
 </dependency>
 ```
 
diff --git a/_config.yml b/_config.yml
deleted file mode 100644
index 2f7efbe..0000000
--- a/_config.yml
+++ /dev/null
@@ -1 +0,0 @@
-theme: jekyll-theme-minimal
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 3d766c2..7dcf4c7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,8 +3,9 @@ plugins {
     id "java-library"
     id "maven-publish"
 
-    id "org.sonarqube" version "3.3"
-    id "com.diffplug.spotless" version "6.12.0"
+    id "org.sonarqube" version "4.3.0.3225"
+    id "com.diffplug.spotless" version "6.19.0"
+    id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
 }
 
 repositories {
@@ -13,7 +14,8 @@ repositories {
 }
 
 group = groupId
-version = artifactVersion
+var ver = System.getenv().getOrDefault("RELEASE_VERSION", artifactVersion)
+version = ver.startsWith("v") ? ver.substring(1) : ver
 
 sourceCompatibility = JavaVersion.VERSION_1_8
 targetCompatibility = JavaVersion.VERSION_1_8
@@ -28,6 +30,7 @@ dependencies {
 }
 
 test {
+    failFast(false)
     useJUnitPlatform()
     testLogging {
         events("passed", "skipped", "failed")
@@ -36,9 +39,13 @@ test {
     }
 
     reports {
-        html.enabled(false)
-        junitXml.enabled(false)
+        html.required = false
+        junitXml.required = false
     }
+
+    environment([
+            "": "",
+    ])
 }
 
 spotless {
@@ -46,7 +53,7 @@ spotless {
         encoding("UTF-8")
         importOrder()
         removeUnusedImports()
-        eclipse("4.21.0").configFile("${rootDir}/config/codestyle.xml")
+        eclipse("4.21").configFile("${rootDir}/config/codestyle.xml")
     }
 }
 
@@ -58,6 +65,18 @@ sonarqube {
     }
 }
 
+nexusPublishing {
+    packageGroup = groupId
+    repositories {
+        sonatype {
+            username = System.getenv("OSS_USERNAME")
+            password = System.getenv("OSS_PASSWORD")
+            nexusUrl.set(uri("https://oss.sonatype.org/service/local/"))
+            snapshotRepositoryUrl.set(uri("https://oss.sonatype.org/content/repositories/snapshots/"))
+        }
+    }
+}
+
 publishing {
     publications {
         mavenJava(MavenPublication) {
@@ -99,6 +118,16 @@ publishing {
                 password System.getenv("OSS_PASSWORD")
             }
         }
+        if (!version.endsWith("SNAPSHOT")) {
+            maven {
+                name = "GitHubPackages"
+                url = "https://maven.pkg.github.com/GoodforGod/$artifactId"
+                credentials {
+                    username = System.getenv("GITHUB_ACTOR")
+                    password = System.getenv("GITHUB_TOKEN")
+                }
+            }
+        }
     }
 }
 
@@ -116,7 +145,7 @@ tasks.withType(JavaCompile) {
 check.dependsOn jacocoTestReport
 jacocoTestReport {
     reports {
-        xml.enabled true
+        xml.required = true
         html.destination file("${buildDir}/jacocoHtml")
     }
 }
@@ -128,9 +157,12 @@ javadoc {
     }
 }
 
-if (project.hasProperty("signing.keyId")) {
+if (project.hasProperty("signingKey")) {
     apply plugin: "signing"
     signing {
+        def signingKey = findProperty("signingKey")
+        def signingPassword = findProperty("signingPassword")
+        useInMemoryPgpKeys(signingKey, signingPassword)
         sign publishing.publications.mavenJava
     }
 }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644
GIT binary patch
delta 36900
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

delta 35022
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
GTKgBj+ffbx

diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 070cb70..a363877 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+networkTimeout=10000
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c787..65dcd68 100755
--- a/gradlew
+++ b/gradlew
@@ -55,7 +55,7 @@
 #       Darwin, MinGW, and NonStop.
 #
 #   (3) This script is generated from the Groovy template
-#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 #       within the Gradle project.
 #
 #       You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,10 +80,10 @@ do
     esac
 done
 
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
 APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
@@ -143,12 +143,16 @@ fi
 if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
     case $MAX_FD in #(
       max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC3045 
         MAX_FD=$( ulimit -H -n ) ||
             warn "Could not query maximum file descriptor limit"
     esac
     case $MAX_FD in  #(
       '' | soft) :;; #(
       *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC3045 
         ulimit -n "$MAX_FD" ||
             warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
@@ -205,6 +209,12 @@ set -- \
         org.gradle.wrapper.GradleWrapperMain \
         "$@"
 
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
 # Use "xargs" to parse quoted args.
 #
 # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd3..93e3f59 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
 @rem limitations under the License.
 @rem
 
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
 @rem ##########################################################################
 @rem
 @rem  Gradle startup script for Windows
@@ -25,7 +25,8 @@
 if "%OS%"=="Windows_NT" setlocal
 
 set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
 
 echo.
 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
 :end
 @rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
 
 :fail
 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
 rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
 
 :mainEnd
 if "%OS%"=="Windows_NT" endlocal

From 40059f487c86ab9f10b13c7191556102760a2011 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Fri, 6 Oct 2023 02:11:01 +0300
Subject: [PATCH 56/67] [2.1.0-SNAPSHOT] CI updated

---
 .github/workflows/publish-release.yml         | 49 +++++++++++++++++++
 .github/workflows/publish-snapshot.yml        | 44 +++++++++++++++++
 .../{gradle.yml => pull-request.yml}          | 34 +++++++------
 3 files changed, 112 insertions(+), 15 deletions(-)
 create mode 100644 .github/workflows/publish-release.yml
 create mode 100644 .github/workflows/publish-snapshot.yml
 rename .github/workflows/{gradle.yml => pull-request.yml} (54%)

diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
new file mode 100644
index 0000000..3aa7884
--- /dev/null
+++ b/.github/workflows/publish-release.yml
@@ -0,0 +1,49 @@
+name: CI Master
+
+on:
+  release:
+    types: [ published ]
+
+jobs:
+  publish-release:
+    runs-on: ubuntu-latest
+    name: Publish Release
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Set up JDK
+        uses: actions/setup-java@v3
+        with:
+          java-version: '17'
+          distribution: 'adopt'
+
+      - name: Build
+        run: './gradlew classes'
+
+      - name: Test
+        run: './gradlew test jacocoTestReport'
+        env:
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
+
+      - name: SonarQube
+        run: './gradlew sonar --info'
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+
+      - name: Publish Release to GitHub Packages
+        run: './gradlew publishMavenJavaPublicationToGitHubPackagesRepository'
+        env:
+          RELEASE_VERSION: ${{ github.ref_name }}
+          GITHUB_TOKEN: ${{ secrets.OSS_GITHUB_TOKEN }}
+          ORG_GRADLE_PROJECT_signingKey: ${{ secrets.OSS_SIGNING_KEY }}
+          ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.OSS_SIGNING_PASSWORD }}
+
+      - name: Publish Release to OSSRH
+        run: './gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository'
+        env:
+          RELEASE_VERSION: ${{ github.ref_name }}
+          OSS_USERNAME: ${{ secrets.OSS_USERNAME }}
+          OSS_PASSWORD: ${{ secrets.OSS_PASSWORD }}
+          ORG_GRADLE_PROJECT_signingKey: ${{ secrets.OSS_SIGNING_KEY }}
+          ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.OSS_SIGNING_PASSWORD }}
diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml
new file mode 100644
index 0000000..d181a6c
--- /dev/null
+++ b/.github/workflows/publish-snapshot.yml
@@ -0,0 +1,44 @@
+name: CI Dev
+
+on:
+  push:
+    paths:
+      - '**/workflows/*.yml'
+      - '**/java/**'
+      - '*.java'
+      - '*.gradle'
+      - '*.properties'
+    branches:
+      - dev
+
+jobs:
+  publish-snapshot:
+    runs-on: ubuntu-latest
+    name: Publish Snapshot
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Set up JDK
+        uses: actions/setup-java@v3
+        with:
+          java-version: '17'
+          distribution: 'adopt'
+
+      - name: Code Style
+        run: './gradlew spotlessCheck'
+
+      - name: Build
+        run: './gradlew classes'
+
+      - name: Test
+        run: './gradlew test jacocoTestReport'
+        env:
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
+
+      - name: Publish Snapshot
+        run: './gradlew publish'
+        env:
+          OSS_USERNAME: ${{ secrets.OSS_USERNAME }}
+          OSS_PASSWORD: ${{ secrets.OSS_PASSWORD }}
+          ORG_GRADLE_PROJECT_signingKey: ${{ secrets.OSS_SIGNING_KEY }}
+          ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.OSS_SIGNING_PASSWORD }}
diff --git a/.github/workflows/gradle.yml b/.github/workflows/pull-request.yml
similarity index 54%
rename from .github/workflows/gradle.yml
rename to .github/workflows/pull-request.yml
index 31c42f0..570e503 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/pull-request.yml
@@ -1,9 +1,6 @@
-name: Java CI
+name: CI Pull Request
 
 on:
-  push:
-    branches:
-      - master
   pull_request:
     branches:
       - master
@@ -15,37 +12,44 @@ jobs:
     strategy:
       matrix:
         java: [ '11', '17' ]
-    name: Java ${{ matrix.java }} setup
+    name: Java ${{ matrix.java }} Pull Request setup
 
     steps:
-      - uses: actions/checkout@v1
+      - uses: actions/checkout@v3
       - name: Set up JDK
-        uses: actions/setup-java@v1
-
+        uses: actions/setup-java@v3
         with:
           java-version: ${{ matrix.java }}
+          distribution: 'adopt'
 
-      - name: Build
-        run: ./gradlew classes
+      - name: Code Style
+        run: './gradlew spotlessCheck'
 
-      - name: Codestyle
-        run: ./gradlew spotlessCheck
+      - name: Build
+        run: './gradlew classes'
 
       - name: Test
         if: matrix.java == '11'
-        run: ./gradlew test jacocoTestReport
+        run: './gradlew test jacocoTestReport'
         env:
           ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_1 }}
 
       - name: Test
         if: matrix.java == '17'
-        run: ./gradlew test jacocoTestReport
+        run: './gradlew test jacocoTestReport'
         env:
           ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
 
       - name: SonarQube
         if: matrix.java == '17'
-        run: ./gradlew sonarqube
+        run: './gradlew sonar --info'
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+
+      - name: Test Report
+        if: matrix.java == '17'
+        uses: EnricoMi/publish-unit-test-result-action@v2
+        with:
+          files: |
+            **/test-results/**/*.xml

From 519c26ae22fdc79e76aab423000b76be91bef339 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Fri, 6 Oct 2023 02:15:47 +0300
Subject: [PATCH 57/67] [2.1.0-SNAPSHOT] Javadoc fixed

---
 src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
index b6db82e..3f48127 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPI.java
@@ -17,7 +17,7 @@ public interface StatisticAPI {
     /**
      * ERC20 token total Supply
      * <a href=
-     * "https://docs.etherscan.io/api-endpoints/tokens#get-erc20-token-totalsupply-by-contractaddress">EtherScan<a>
+     * "https://docs.etherscan.io/api-endpoints/tokens#get-erc20-token-totalsupply-by-contractaddress">EtherScan</a>
      * Returns the current amount of an ERC-20 token in circulation.
      *
      * @param contract contract address

From b6e9ba5e988fefa805db78f10bdac90cb1b98c6e Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Fri, 6 Oct 2023 02:21:15 +0300
Subject: [PATCH 58/67] [2.1.0-SNAPSHOT] Method renamed

---
 .../java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java     | 2 +-
 src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java     | 2 +-
 src/test/java/io/goodforgod/api/etherscan/ApiRunner.java        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index 70d9a01..2b70711 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -89,7 +89,7 @@ public EtherScanAPI.Builder withConverter(@NotNull Supplier<Converter> converter
     }
 
     @NotNull
-    public EtherScanAPI.Builder withRetryOnLimitReach(int maxRetryCount) {
+    public EtherScanAPI.Builder withRetryOnRateLimit(int maxRetryCount) {
         if (maxRetryCount < 0 || maxRetryCount > 20) {
             throw new IllegalStateException("maxRetryCount value must be in range from 0 to 20, but was: " + maxRetryCount);
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
index 4e6bc57..bae1902 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -71,7 +71,7 @@ interface Builder {
          * @return self
          */
         @NotNull
-        EtherScanAPI.Builder withRetryOnLimitReach(@Range(from = 0, to = 20) int maxRetryCount);
+        EtherScanAPI.Builder withRetryOnRateLimit(@Range(from = 0, to = 20) int maxRetryCount);
 
         @NotNull
         EtherScanAPI build();
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index 72aeeff..bc4f334 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -29,7 +29,7 @@ public class ApiRunner extends Assertions {
                 .withApiKey(ApiRunner.API_KEY)
                 .withNetwork(EthNetworks.MAINNET)
                 .withQueue(queueManager)
-                .withRetryOnLimitReach(5)
+                .withRetryOnRateLimit(5)
                 .build();
     }
 

From c855695fdc61fb978bf0c86669ee476c051915b9 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Fri, 6 Oct 2023 02:21:55 +0300
Subject: [PATCH 59/67] [2.1.0-SNAPSHOT] Method renamed

---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 7dcf4c7..7e28207 100644
--- a/build.gradle
+++ b/build.gradle
@@ -40,7 +40,7 @@ test {
 
     reports {
         html.required = false
-        junitXml.required = false
+        junitXml.required = true
     }
 
     environment([

From 3a252b4e32ebc5e4408ca25c903fb3776e5458ac Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Fri, 6 Oct 2023 02:22:51 +0300
Subject: [PATCH 60/67] [2.1.0-SNAPSHOT] CI updated

---
 .github/workflows/pull-request.yml | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 570e503..0b49f50 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -40,16 +40,16 @@ jobs:
         env:
           ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
 
-      - name: SonarQube
-        if: matrix.java == '17'
-        run: './gradlew sonar --info'
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
-
       - name: Test Report
         if: matrix.java == '17'
         uses: EnricoMi/publish-unit-test-result-action@v2
         with:
           files: |
             **/test-results/**/*.xml
+
+      - name: SonarQube
+        if: matrix.java == '17'
+        run: './gradlew sonar --info'
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

From 3de7b242b9f65daaaedbec0ef67ea83fd45c0706 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 15 Jan 2024 12:39:58 +0300
Subject: [PATCH 61/67] [2.1.0-SNAPSHOT] README.md updated

---
 README.md | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/README.md b/README.md
index c086a6b..0d06c99 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ API support all Ethereum [default networks](https://docs.etherscan.io/getting-st
 - [Sepolia](https://api-sepolia.etherscan.io/)
 
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 EtherScanAPI apiGoerli = EtherScanAPI.builder().withNetwork(EthNetworks.GORLI).build();
 EtherScanAPI apiSepolia = EtherScanAPI.builder().withNetwork(EthNetworks.SEPOLIA).build();
 ```
@@ -97,7 +97,7 @@ Below are examples for each API category.
 
 **Get Ether Balance for a single Address**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
 ```
 
@@ -105,14 +105,14 @@ Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3
 
 **Get uncles block for block height**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 Optional<UncleBlock> uncles = api.block().uncles(200000);
 ```
 
 ### Contract API
 **Request contract ABI from [verified codes](https://etherscan.io/contractsVerified)**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 Abi abi = api.contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413");
 ```
 
@@ -120,7 +120,7 @@ Abi abi = api.contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413
 
 **Get event logs for single topic**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 LogQuery query = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
            .withTopic("0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545")
            .build();
@@ -129,7 +129,7 @@ List<Log> logs = api.logs().logs(query);
 
 **Get event logs for 3 topics with respectful operations**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 LogQuery query = LogQuery.builder("0x33990122638b9132ca29c723bdf037f1a891a70c")
         .withBlockFrom(379224)
         .withBlockTo(400000)
@@ -148,13 +148,13 @@ List<Log> logs = api.logs().logs(query);
 
 **Get tx details with proxy endpoint**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 Optional<TxProxy> tx = api.proxy().tx("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
 ```
 
 **Get block info with proxy endpoint**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 Optional<BlockProxy> block = api.proxy().block(15215);
 ```
 
@@ -162,7 +162,7 @@ Optional<BlockProxy> block = api.proxy().block(15215);
 
 **Statistic about last price**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 Price price = api.stats().priceLast();
 ```
 
@@ -170,7 +170,7 @@ Price price = api.stats().priceLast();
 
 **Request receipt status for tx**
 ```java
-EtherScanAPI api = EtherScanAPI.build();
+EtherScanAPI api = EtherScanAPI.builder().build();
 Optional<Boolean> status = api.txs().receiptStatus("0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
 ```
 

From bb87f9014587b7e83a5b6c7ffa898d840b117587 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 7 Sep 2025 15:09:54 +0300
Subject: [PATCH 62/67] [3.0.0-SNAPSHOT] Added JdkEthHttpClient All contracts
 open or protected Updated dependencies Updated Gradle

---
 README.md                                     |  14 +-
 build.gradle                                  |  16 +-
 gradle.properties                             |   2 +-
 gradle/wrapper/gradle-wrapper.jar             | Bin 61574 -> 43764 bytes
 gradle/wrapper/gradle-wrapper.properties      |   3 +-
 gradlew                                       |  37 +++--
 gradlew.bat                                   |  26 +--
 .../api/etherscan/AccountAPIProvider.java     |  50 ++----
 .../api/etherscan/BasicProvider.java          |  81 +++++++---
 .../api/etherscan/BlockAPIProvider.java       |  14 +-
 .../api/etherscan/ContractAPIProvider.java    |  16 +-
 .../api/etherscan/EthScanAPIBuilder.java      |   6 +-
 .../api/etherscan/EtherScanAPIProvider.java   |  14 +-
 .../api/etherscan/GasTrackerAPIProvider.java  |  16 +-
 .../api/etherscan/LogsAPIProvider.java        |  14 +-
 .../api/etherscan/ProxyAPIProvider.java       |  38 ++---
 .../api/etherscan/StatisticAPIProvider.java   |  20 +--
 .../api/etherscan/TransactionAPIProvider.java |  16 +-
 .../EtherScanConnectionTimeoutException.java  |  12 ++
 .../error/EtherScanTimeoutException.java      |  12 --
 .../api/etherscan/http/EthHttpClient.java     |   4 +-
 .../api/etherscan/http/EthResponse.java       |  30 ++++
 .../api/etherscan/http/SimpleEthResponse.java |  64 ++++++++
 .../etherscan/http/impl/JdkEthHttpClient.java | 148 ++++++++++++++++++
 .../etherscan/http/impl/UrlEthHttpClient.java |  58 ++++---
 .../manager/impl/FakeRequestQueueManager.java |   2 +-
 .../impl/SemaphoreRequestQueueManager.java    |   2 +-
 .../goodforgod/api/etherscan/model/Abi.java   |   2 +-
 .../api/etherscan/model/BaseTx.java           |   2 +-
 .../api/etherscan/model/BlockTx.java          |   2 +-
 .../api/etherscan/model/BlockUncle.java       |   4 +-
 .../api/etherscan/model/ContractCreation.java |   2 +-
 .../api/etherscan/model/EthSupply.java        |   2 +-
 .../api/etherscan/model/GasOracle.java        |   2 +-
 .../goodforgod/api/etherscan/model/Log.java   |   2 +-
 .../goodforgod/api/etherscan/model/Price.java |   2 +-
 .../api/etherscan/model/Status.java           |   2 +-
 .../io/goodforgod/api/etherscan/model/Tx.java |   2 +-
 .../api/etherscan/model/TxErc1155.java        |   2 +-
 .../api/etherscan/model/TxErc20.java          |   2 +-
 .../api/etherscan/model/TxErc721.java         |   2 +-
 .../api/etherscan/model/TxInternal.java       |   2 +-
 .../api/etherscan/model/proxy/BlockProxy.java |   2 +-
 .../etherscan/model/proxy/ReceiptProxy.java   |   2 +-
 .../api/etherscan/model/proxy/TxProxy.java    |   2 +-
 .../model/proxy/utility/BaseProxyTO.java      |   2 +-
 .../model/query/LogQueryBuilderImpl.java      |   2 +-
 .../etherscan/model/query/LogQueryImpl.java   |   2 +-
 .../etherscan/model/query/LogQueryParams.java |   2 +-
 .../etherscan/model/query/LogTopicQuadro.java |   2 +-
 .../etherscan/model/query/LogTopicSingle.java |   2 +-
 .../etherscan/model/query/LogTopicTriple.java |   2 +-
 .../etherscan/model/query/LogTopicTuple.java  |   2 +-
 .../model/response/StringResponseTO.java      |   2 +-
 .../api/etherscan/util/BasicUtils.java        |   2 +-
 55 files changed, 536 insertions(+), 237 deletions(-)
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionTimeoutException.java
 delete mode 100644 src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/http/EthResponse.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/http/SimpleEthResponse.java
 create mode 100644 src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java

diff --git a/README.md b/README.md
index 0d06c99..160f8e4 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ Library supports EtherScan *API* for all available *Ethereum Networks* for *ethe
 
 **Gradle**
 ```groovy
-implementation "com.github.goodforgod:java-etherscan-api:2.1.0"
+implementation "com.github.goodforgod:java-etherscan-api:3.0.0"
 ```
 
 **Maven**
@@ -23,7 +23,7 @@ implementation "com.github.goodforgod:java-etherscan-api:2.1.0"
 <dependency>
     <groupId>com.github.goodforgod</groupId>
     <artifactId>java-etherscan-api</artifactId>
-    <version>2.1.0</version>
+    <version>3.0.0</version>
 </dependency>
 ```
 
@@ -76,6 +76,14 @@ EtherScanAPI api = EtherScanAPI.builder()
     .build();
 ```
 
+Also you can use Java 11+ HttpClient:
+```java
+Supplier<EthHttpClient> ethHttpClientSupplier = () -> new JdkEthHttpClient();
+EtherScanAPI api = EtherScanAPI.builder()
+    .withHttpClient(supplier)
+    .build();
+```
+
 ## API Examples
 
 You can read about all API methods on [Etherscan](https://docs.etherscan.io/api-endpoints/accounts)
@@ -149,7 +157,7 @@ List<Log> logs = api.logs().logs(query);
 **Get tx details with proxy endpoint**
 ```java
 EtherScanAPI api = EtherScanAPI.builder().build();
-Optional<TxProxy> tx = api.proxy().tx("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
+Optional<TxProxy> tx = api.proxy().tx("0x1e2910a263.0.08d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
 ```
 
 **Get block info with proxy endpoint**
diff --git a/build.gradle b/build.gradle
index 7e28207..f946f1d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,9 @@ plugins {
     id "java-library"
     id "maven-publish"
 
-    id "org.sonarqube" version "4.3.0.3225"
+    id "org.sonarqube" version "6.3.1.5724"
     id "com.diffplug.spotless" version "6.19.0"
-    id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
+    id "io.github.gradle-nexus.publish-plugin" version "2.0.0"
 }
 
 repositories {
@@ -17,16 +17,16 @@ group = groupId
 var ver = System.getenv().getOrDefault("RELEASE_VERSION", artifactVersion)
 version = ver.startsWith("v") ? ver.substring(1) : ver
 
-sourceCompatibility = JavaVersion.VERSION_1_8
-targetCompatibility = JavaVersion.VERSION_1_8
+sourceCompatibility = JavaVersion.VERSION_11
+targetCompatibility = JavaVersion.VERSION_11
 
 dependencies {
-    compileOnly "org.jetbrains:annotations:23.0.0"
+    compileOnly "org.jetbrains:annotations:24.0.1"
     implementation "io.goodforgod:gson-configuration:2.0.0"
 
-    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.3"
-    testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.3"
-    testImplementation "org.junit.jupiter:junit-jupiter-params:5.9.3"
+    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4"
+    testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4"
+    testImplementation "org.junit.jupiter:junit-jupiter-params:5.11.4"
 }
 
 test {
diff --git a/gradle.properties b/gradle.properties
index ee5fd3b..7b97567 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,6 @@
 groupId=com.github.goodforgod
 artifactId=java-etherscan-api
-artifactVersion=2.1.0-SNAPSHOT
+artifactVersion=3.0.0-SNAPSHOT
 
 
 ##### GRADLE #####
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..1b33c55baabb587c669f562ae36f953de2481846 100644
GIT binary patch
literal 43764
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
Mi07c5C&+LA2gVWY(f|Me

literal 61574
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%0D=uyzE7ST
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
ScNgau(U?ep-K_E5zy1%ZQTdPn

diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a363877..d4081da 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
 networkTimeout=10000
+validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 65dcd68..23d15a9 100755
--- a/gradlew
+++ b/gradlew
@@ -15,6 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+# SPDX-License-Identifier: Apache-2.0
+#
 
 ##############################################################################
 #
@@ -55,7 +57,7 @@
 #       Darwin, MinGW, and NonStop.
 #
 #   (3) This script is generated from the Groovy template
-#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 #       within the Gradle project.
 #
 #       You can find Gradle at https://github.com/gradle/gradle/.
@@ -83,10 +85,8 @@ done
 # This is normally unused
 # shellcheck disable=SC2034
 APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD=maximum
@@ -114,7 +114,7 @@ case "$( uname )" in                #(
   NONSTOP* )        nonstop=true ;;
 esac
 
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+CLASSPATH="\\\"\\\""
 
 
 # Determine the Java command to use to start the JVM.
@@ -133,10 +133,13 @@ location of your Java installation."
     fi
 else
     JAVACMD=java
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
+    fi
 fi
 
 # Increase the maximum file descriptors if we can.
@@ -144,7 +147,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
     case $MAX_FD in #(
       max*)
         # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
-        # shellcheck disable=SC3045 
+        # shellcheck disable=SC2039,SC3045
         MAX_FD=$( ulimit -H -n ) ||
             warn "Could not query maximum file descriptor limit"
     esac
@@ -152,7 +155,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
       '' | soft) :;; #(
       *)
         # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
-        # shellcheck disable=SC3045 
+        # shellcheck disable=SC2039,SC3045
         ulimit -n "$MAX_FD" ||
             warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
@@ -197,16 +200,20 @@ if "$cygwin" || "$msys" ; then
     done
 fi
 
-# Collect all arguments for the java command;
-#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-#     shell script including quotes and variable substitutions, so put them in
-#     double quotes to make sure that they get re-expanded; and
-#   * put everything else in single quotes, so that it's not re-expanded.
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#     and any embedded shellness will be escaped.
+#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+#     treated as '${Hostname}' itself on the command line.
 
 set -- \
         "-Dorg.gradle.appname=$APP_BASE_NAME" \
         -classpath "$CLASSPATH" \
-        org.gradle.wrapper.GradleWrapperMain \
+        -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
         "$@"
 
 # Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 93e3f59..db3a6ac 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
 @rem See the License for the specific language governing permissions and
 @rem limitations under the License.
 @rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
 
 @if "%DEBUG%"=="" @echo off
 @rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
 if %ERRORLEVEL% equ 0 goto execute
 
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
 
 goto fail
 
@@ -57,22 +59,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 
 if exist "%JAVA_EXE%" goto execute
 
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
 
 goto fail
 
 :execute
 @rem Setup the command line
 
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+set CLASSPATH=
 
 
 @rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
 
 :end
 @rem End local scope for the variables with windows NT shell
diff --git a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
index 750d525..aceb9a2 100644
--- a/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/AccountAPIProvider.java
@@ -21,9 +21,9 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-final class AccountAPIProvider extends BasicProvider implements AccountAPI {
+public class AccountAPIProvider extends BasicProvider implements AccountAPI {
 
-    private static final int OFFSET_MAX = 10000;
+    private static final int OFFSET_MAX = 9999;
 
     private static final String ACT_BALANCE_ACTION = ACT_PREFIX + "balance";
     private static final String ACT_TOKEN_BALANCE_PARAM = ACT_PREFIX + "tokenbalance";
@@ -47,11 +47,11 @@ final class AccountAPIProvider extends BasicProvider implements AccountAPI {
     private static final String OFFSET_PARAM = "&offset=";
     private static final String PAGE_PARAM = "&page=";
 
-    AccountAPIProvider(RequestQueueManager requestQueueManager,
-                       String baseUrl,
-                       EthHttpClient executor,
-                       Converter converter,
-                       int retryCount) {
+    public AccountAPIProvider(RequestQueueManager requestQueueManager,
+                              String baseUrl,
+                              EthHttpClient executor,
+                              Converter converter,
+                              int retryCount) {
         super(requestQueueManager, "account", baseUrl, executor, converter, retryCount);
     }
 
@@ -61,7 +61,7 @@ public Balance balance(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_BALANCE_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM + address;
-        final StringResponseTO response = getRequest(urlParams, StringResponseTO.class);
+        final StringResponseTO response = getResponse(urlParams, StringResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
@@ -75,7 +75,7 @@ public TokenBalance balance(@NotNull String address, @NotNull String contract) t
         BasicUtils.validateAddress(contract);
 
         final String urlParams = ACT_TOKEN_BALANCE_PARAM + ADDRESS_PARAM + address + CONTRACT_PARAM + contract;
-        final StringResponseTO response = getRequest(urlParams, StringResponseTO.class);
+        final StringResponseTO response = getResponse(urlParams, StringResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
@@ -98,7 +98,7 @@ public List<Balance> balances(@NotNull List<String> addresses) throws EtherScanE
         for (final List<String> batch : addressesAsBatches) {
             final String urlParams = ACT_BALANCE_MULTI_ACTION + TAG_LATEST_PARAM + ADDRESS_PARAM
                     + BasicUtils.toAddressParam(batch);
-            final BalanceResponseTO response = getRequest(urlParams, BalanceResponseTO.class);
+            final BalanceResponseTO response = getResponse(urlParams, BalanceResponseTO.class);
             if (response.getStatus() != 1) {
                 throw new EtherScanResponseException(response);
             }
@@ -139,34 +139,6 @@ public List<Tx> txs(@NotNull String address, long startBlock, long endBlock) thr
         return getRequestUsingOffset(urlParams, TxResponseTO.class);
     }
 
-    /**
-     * Generic search for txs using offset api param To avoid 10k limit per response
-     *
-     * @param urlParams Url params for #getRequest()
-     * @param tClass    responseListTO class
-     * @param <T>       responseTO list T type
-     * @param <R>       responseListTO type
-     * @return List of T values
-     */
-    private <T, R extends BaseListResponseTO<T>> List<T> getRequestUsingOffset(final String urlParams, Class<R> tClass)
-            throws EtherScanException {
-        final List<T> result = new ArrayList<>();
-        int page = 1;
-        while (true) {
-            final String formattedUrl = String.format(urlParams, page++);
-            final R response = getRequest(formattedUrl, tClass);
-            BasicUtils.validateTxResponse(response);
-            if (BasicUtils.isEmpty(response.getResult()))
-                break;
-
-            result.addAll(response.getResult());
-            if (response.getResult().size() < OFFSET_MAX)
-                break;
-        }
-
-        return result;
-    }
-
     @NotNull
     @Override
     public List<TxInternal> txsInternal(@NotNull String address) throws EtherScanException {
@@ -200,7 +172,7 @@ public List<TxInternal> txsInternalByHash(@NotNull String txhash) throws EtherSc
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_INTERNAL_ACTION + TXHASH_PARAM + txhash;
-        final TxInternalResponseTO response = getRequest(urlParams, TxInternalResponseTO.class);
+        final TxInternalResponseTO response = getResponse(urlParams, TxInternalResponseTO.class);
         BasicUtils.validateTxResponse(response);
 
         return BasicUtils.isEmpty(response.getResult())
diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 41abd16..2abb2e0 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -1,13 +1,21 @@
 package io.goodforgod.api.etherscan;
 
+import io.goodforgod.api.etherscan.error.EtherScanException;
 import io.goodforgod.api.etherscan.error.EtherScanParseException;
 import io.goodforgod.api.etherscan.error.EtherScanRateLimitException;
 import io.goodforgod.api.etherscan.error.EtherScanResponseException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthResponse;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
+import io.goodforgod.api.etherscan.model.response.BaseListResponseTO;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import io.goodforgod.api.etherscan.util.BasicUtils;
+import org.jetbrains.annotations.ApiStatus.Internal;
 
 /**
  * Base provider for API Implementations
@@ -16,10 +24,13 @@
  * @see EtherScanAPIProvider
  * @since 28.10.2018
  */
-abstract class BasicProvider {
+@Internal
+public abstract class BasicProvider {
 
     private static final String MAX_RATE_LIMIT_REACHED = "Max rate limit reached";
 
+    private static final int OFFSET_MAX = 9999;
+
     static final int MAX_END_BLOCK = Integer.MAX_VALUE;
     static final int MIN_START_BLOCK = 0;
 
@@ -32,12 +43,12 @@ abstract class BasicProvider {
     private final Converter converter;
     private final int retryCountLimit;
 
-    BasicProvider(RequestQueueManager requestQueueManager,
-                  String module,
-                  String baseUrl,
-                  EthHttpClient ethHttpClient,
-                  Converter converter,
-                  int retryCountLimit) {
+    public BasicProvider(RequestQueueManager requestQueueManager,
+                         String module,
+                         String baseUrl,
+                         EthHttpClient ethHttpClient,
+                         Converter converter,
+                         int retryCountLimit) {
         this.queue = requestQueueManager;
         this.module = "&module=" + module;
         this.baseUrl = baseUrl;
@@ -46,7 +57,7 @@ abstract class BasicProvider {
         this.retryCountLimit = retryCountLimit;
     }
 
-    private <T> T convert(byte[] json, Class<T> tClass) {
+    protected <T> T convert(byte[] json, Class<T> tClass) {
         try {
             final T t = converter.fromJson(json, tClass);
             if (t instanceof StringResponseTO && ((StringResponseTO) t).getResult().startsWith(MAX_RATE_LIMIT_REACHED)) {
@@ -69,25 +80,58 @@ private <T> T convert(byte[] json, Class<T> tClass) {
         }
     }
 
-    private byte[] getRequest(String urlParameters) {
+    protected int getMaximumOffset() {
+        return OFFSET_MAX;
+    }
+
+    /**
+     * Generic search for txs using offset api param To avoid 10k limit per response
+     *
+     * @param urlParams Url params for #getRequest()
+     * @param tClass    responseListTO class
+     * @param <T>       responseTO list T type
+     * @param <R>       responseListTO type
+     * @return List of T values
+     */
+    protected <T, R extends BaseListResponseTO<T>> List<T> getRequestUsingOffset(final String urlParams, Class<R> tClass)
+            throws EtherScanException {
+        final List<T> result = new ArrayList<>();
+        int page = 1;
+        while (true) {
+            final String formattedUrl = String.format(urlParams, page++);
+            final R response = getResponse(formattedUrl, tClass);
+            BasicUtils.validateTxResponse(response);
+            if (BasicUtils.isEmpty(response.getResult()))
+                break;
+
+            result.addAll(response.getResult());
+            if (response.getResult().size() < getMaximumOffset())
+                break;
+        }
+
+        return result;
+    }
+
+    protected EthResponse getResponse(String urlParameters) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
         return executor.get(uri);
     }
 
-    private byte[] postRequest(String urlParameters, String dataToPost) {
+    protected EthResponse postRequest(String urlParameters, String dataToPost) {
         queue.takeTurn();
         final URI uri = URI.create(baseUrl + module + urlParameters);
         return executor.post(uri, dataToPost.getBytes(StandardCharsets.UTF_8));
     }
 
-    <T> T getRequest(String urlParameters, Class<T> tClass) {
-        return getRequest(urlParameters, tClass, 0);
+    protected <T> T getResponse(String urlParameters, Class<T> tClass) {
+        return getResponse(urlParameters, tClass, 0);
     }
 
-    private <T> T getRequest(String urlParameters, Class<T> tClass, int retryCount) {
+    protected <T> T getResponse(String urlParameters, Class<T> tClass, int retryCount) {
         try {
-            return convert(getRequest(urlParameters), tClass);
+            EthResponse response = getResponse(urlParameters);
+            return convert(response.body(), tClass);
         } catch (Exception e) {
             if (retryCount < retryCountLimit) {
                 try {
@@ -96,20 +140,21 @@ private <T> T getRequest(String urlParameters, Class<T> tClass, int retryCount)
                     throw new IllegalStateException(ex);
                 }
 
-                return getRequest(urlParameters, tClass, retryCount + 1);
+                return getResponse(urlParameters, tClass, retryCount + 1);
             } else {
                 throw e;
             }
         }
     }
 
-    <T> T postRequest(String urlParameters, String dataToPost, Class<T> tClass) {
+    protected <T> T postRequest(String urlParameters, String dataToPost, Class<T> tClass) {
         return postRequest(urlParameters, dataToPost, tClass, 0);
     }
 
-    private <T> T postRequest(String urlParameters, String dataToPost, Class<T> tClass, int retryCount) {
+    protected <T> T postRequest(String urlParameters, String dataToPost, Class<T> tClass, int retryCount) {
         try {
-            return convert(postRequest(urlParameters, dataToPost), tClass);
+            EthResponse response = postRequest(urlParameters, dataToPost);
+            return convert(response.body(), tClass);
         } catch (EtherScanRateLimitException e) {
             if (retryCount < retryCountLimit) {
                 try {
diff --git a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
index b3604a7..7228943 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BlockAPIProvider.java
@@ -17,17 +17,17 @@
  * @see BlockAPI
  * @since 28.10.2018
  */
-final class BlockAPIProvider extends BasicProvider implements BlockAPI {
+public class BlockAPIProvider extends BasicProvider implements BlockAPI {
 
     private static final String ACT_BLOCK_PARAM = ACT_PREFIX + "getblockreward";
 
     private static final String BLOCKNO_PARAM = "&blockno=";
 
-    BlockAPIProvider(RequestQueueManager requestQueueManager,
-                     String baseUrl,
-                     EthHttpClient executor,
-                     Converter converter,
-                     int retryCount) {
+    public BlockAPIProvider(RequestQueueManager requestQueueManager,
+                            String baseUrl,
+                            EthHttpClient executor,
+                            Converter converter,
+                            int retryCount) {
         super(requestQueueManager, "block", baseUrl, executor, converter, retryCount);
     }
 
@@ -36,7 +36,7 @@ final class BlockAPIProvider extends BasicProvider implements BlockAPI {
     public Optional<BlockUncle> uncles(long blockNumber) throws EtherScanException {
         final String urlParam = ACT_BLOCK_PARAM + BLOCKNO_PARAM + blockNumber;
         try {
-            final UncleBlockResponseTO responseTO = getRequest(urlParam, UncleBlockResponseTO.class);
+            final UncleBlockResponseTO responseTO = getResponse(urlParam, UncleBlockResponseTO.class);
             if (responseTO.getMessage().startsWith("NOTOK")) {
                 return Optional.empty();
             }
diff --git a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
index 898a7b7..0719569 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ContractAPIProvider.java
@@ -20,7 +20,7 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-final class ContractAPIProvider extends BasicProvider implements ContractAPI {
+public class ContractAPIProvider extends BasicProvider implements ContractAPI {
 
     private static final String ACT_ABI_PARAM = ACT_PREFIX + "getabi";
 
@@ -32,11 +32,11 @@ final class ContractAPIProvider extends BasicProvider implements ContractAPI {
 
     private static final String ACT_CONTRACT_ADDRESSES_PARAM = "&contractaddresses=";
 
-    ContractAPIProvider(RequestQueueManager requestQueueManager,
-                        String baseUrl,
-                        EthHttpClient executor,
-                        Converter converter,
-                        int retryCount) {
+    public ContractAPIProvider(RequestQueueManager requestQueueManager,
+                               String baseUrl,
+                               EthHttpClient executor,
+                               Converter converter,
+                               int retryCount) {
         super(requestQueueManager, "contract", baseUrl, executor, converter, retryCount);
     }
 
@@ -46,7 +46,7 @@ public Abi contractAbi(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParam = ACT_ABI_PARAM + ADDRESS_PARAM + address;
-        final StringResponseTO response = getRequest(urlParam, StringResponseTO.class);
+        final StringResponseTO response = getResponse(urlParam, StringResponseTO.class);
         if (response.getStatus() != 1 && response.getMessage().startsWith("NOTOK")) {
             throw new EtherScanResponseException(response);
         }
@@ -62,7 +62,7 @@ public List<ContractCreation> contractCreation(@NotNull List<String> contractAdd
         BasicUtils.validateAddresses(contractAddresses);
         final String urlParam = ACT_CONTRACT_CREATION + ACT_CONTRACT_ADDRESSES_PARAM
                 + BasicUtils.toAddressParam(contractAddresses);
-        final ContractCreationResponseTO response = getRequest(urlParam, ContractCreationResponseTO.class);
+        final ContractCreationResponseTO response = getResponse(urlParam, ContractCreationResponseTO.class);
         if (response.getStatus() != 1 && response.getMessage().startsWith("NOTOK")) {
             throw new EtherScanResponseException(response);
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index 2b70711..12bb9d3 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -4,7 +4,7 @@
 import io.goodforgod.api.etherscan.error.EtherScanKeyException;
 import io.goodforgod.api.etherscan.error.EtherScanParseException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
-import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
+import io.goodforgod.api.etherscan.http.impl.JdkEthHttpClient;
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.util.BasicUtils;
 import io.goodforgod.gson.configuration.GsonConfiguration;
@@ -19,9 +19,9 @@
  * @author Anton Kurako (GoodforGod)
  * @since 11.05.2023
  */
-final class EthScanAPIBuilder implements EtherScanAPI.Builder {
+public class EthScanAPIBuilder implements EtherScanAPI.Builder {
 
-    private static final Supplier<EthHttpClient> DEFAULT_SUPPLIER = UrlEthHttpClient::new;
+    private static final Supplier<EthHttpClient> DEFAULT_SUPPLIER = JdkEthHttpClient::new;
     private static final String DEFAULT_KEY = "YourApiKeyToken";
 
     private final Gson gson = new GsonConfiguration().builder().create();
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
index ab6e863..daf1e4a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPIProvider.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-final class EtherScanAPIProvider implements EtherScanAPI {
+public class EtherScanAPIProvider implements EtherScanAPI {
 
     private final RequestQueueManager requestQueueManager;
     private final AccountAPI account;
@@ -22,12 +22,12 @@ final class EtherScanAPIProvider implements EtherScanAPI {
     private final TransactionAPI txs;
     private final GasTrackerAPI gasTracker;
 
-    EtherScanAPIProvider(String apiKey,
-                         EthNetwork network,
-                         RequestQueueManager queue,
-                         EthHttpClient ethHttpClient,
-                         Converter converter,
-                         int retryCount) {
+    public EtherScanAPIProvider(String apiKey,
+                                EthNetwork network,
+                                RequestQueueManager queue,
+                                EthHttpClient ethHttpClient,
+                                Converter converter,
+                                int retryCount) {
         // EtherScan 1request\5sec limit support by queue manager
         final String baseUrl = network.domain() + "?apikey=" + apiKey;
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
index ed717a9..e7ecb7c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/GasTrackerAPIProvider.java
@@ -18,25 +18,25 @@
  * @author Abhay Gupta
  * @since 14.11.2022
  */
-final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI {
+public class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI {
 
     private static final String ACT_GAS_ORACLE_PARAM = ACT_PREFIX + "gasoracle";
     private static final String ACT_GAS_ESTIMATE_PARAM = ACT_PREFIX + "gasestimate";
 
     private static final String GASPRICE_PARAM = "&gasprice=";
 
-    GasTrackerAPIProvider(RequestQueueManager queue,
-                          String baseUrl,
-                          EthHttpClient ethHttpClient,
-                          Converter converter,
-                          int retryCount) {
+    public GasTrackerAPIProvider(RequestQueueManager queue,
+                                 String baseUrl,
+                                 EthHttpClient ethHttpClient,
+                                 Converter converter,
+                                 int retryCount) {
         super(queue, "gastracker", baseUrl, ethHttpClient, converter, retryCount);
     }
 
     @Override
     public @NotNull Duration estimate(@NotNull Wei wei) throws EtherScanException {
         final String urlParams = ACT_GAS_ESTIMATE_PARAM + GASPRICE_PARAM + wei.asWei().toString();
-        final GasEstimateResponseTO response = getRequest(urlParams, GasEstimateResponseTO.class);
+        final GasEstimateResponseTO response = getResponse(urlParams, GasEstimateResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
@@ -46,7 +46,7 @@ final class GasTrackerAPIProvider extends BasicProvider implements GasTrackerAPI
     @NotNull
     @Override
     public GasOracle oracle() throws EtherScanException {
-        final GasOracleResponseTO response = getRequest(ACT_GAS_ORACLE_PARAM, GasOracleResponseTO.class);
+        final GasOracleResponseTO response = getResponse(ACT_GAS_ORACLE_PARAM, GasOracleResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
index 237cafd..1002dc8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/LogsAPIProvider.java
@@ -18,15 +18,15 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-final class LogsAPIProvider extends BasicProvider implements LogsAPI {
+public class LogsAPIProvider extends BasicProvider implements LogsAPI {
 
     private static final String ACT_LOGS_PARAM = ACT_PREFIX + "getLogs";
 
-    LogsAPIProvider(RequestQueueManager queue,
-                    String baseUrl,
-                    EthHttpClient executor,
-                    Converter converter,
-                    int retryCount) {
+    public LogsAPIProvider(RequestQueueManager queue,
+                           String baseUrl,
+                           EthHttpClient executor,
+                           Converter converter,
+                           int retryCount) {
         super(queue, "logs", baseUrl, executor, converter, retryCount);
     }
 
@@ -34,7 +34,7 @@ final class LogsAPIProvider extends BasicProvider implements LogsAPI {
     @Override
     public List<Log> logs(@NotNull LogQuery query) throws EtherScanException {
         final String urlParams = ACT_LOGS_PARAM + query.params();
-        final LogResponseTO response = getRequest(urlParams, LogResponseTO.class);
+        final LogResponseTO response = getResponse(urlParams, LogResponseTO.class);
         BasicUtils.validateTxResponse(response);
 
         return (BasicUtils.isEmpty(response.getResult()))
diff --git a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
index 428b48f..e35fd08 100644
--- a/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/ProxyAPIProvider.java
@@ -26,7 +26,7 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-final class ProxyAPIProvider extends BasicProvider implements ProxyAPI {
+public class ProxyAPIProvider extends BasicProvider implements ProxyAPI {
 
     private static final String ACT_BLOCKNO_PARAM = ACT_PREFIX + "eth_blockNumber";
     private static final String ACT_BY_BLOCKNO_PARAM = ACT_PREFIX + "eth_getBlockByNumber";
@@ -57,17 +57,17 @@ final class ProxyAPIProvider extends BasicProvider implements ProxyAPI {
 
     private static final Pattern EMPTY_HEX = Pattern.compile("0x0+");
 
-    ProxyAPIProvider(RequestQueueManager queue,
-                     String baseUrl,
-                     EthHttpClient executor,
-                     Converter converter,
-                     int retryCount) {
+    public ProxyAPIProvider(RequestQueueManager queue,
+                            String baseUrl,
+                            EthHttpClient executor,
+                            Converter converter,
+                            int retryCount) {
         super(queue, "proxy", baseUrl, executor, converter, retryCount);
     }
 
     @Override
     public long blockNoLast() throws EtherScanException {
-        final StringProxyTO response = getRequest(ACT_BLOCKNO_PARAM, StringProxyTO.class);
+        final StringProxyTO response = getResponse(ACT_BLOCKNO_PARAM, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
                 ? -1
                 : BasicUtils.parseHex(response.getResult()).longValue();
@@ -79,7 +79,7 @@ public Optional<BlockProxy> block(long blockNo) throws EtherScanException {
         final long compBlockNo = BasicUtils.compensateMinBlock(blockNo);
 
         final String urlParams = ACT_BY_BLOCKNO_PARAM + TAG_PARAM + compBlockNo + BOOLEAN_PARAM;
-        final BlockProxyTO response = getRequest(urlParams, BlockProxyTO.class);
+        final BlockProxyTO response = getResponse(urlParams, BlockProxyTO.class);
         return Optional.ofNullable(response.getResult());
     }
 
@@ -91,7 +91,7 @@ public Optional<BlockProxy> blockUncle(long blockNo, long index) throws EtherSca
 
         final String urlParams = ACT_UNCLE_BY_BLOCKNOINDEX_PARAM + TAG_PARAM
                 + "0x" + Long.toHexString(compBlockNo) + INDEX_PARAM + "0x" + Long.toHexString(compIndex);
-        final BlockProxyTO response = getRequest(urlParams, BlockProxyTO.class);
+        final BlockProxyTO response = getResponse(urlParams, BlockProxyTO.class);
         return Optional.ofNullable(response.getResult());
     }
 
@@ -101,7 +101,7 @@ public Optional<TxProxy> tx(@NotNull String txhash) throws EtherScanException {
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_BY_HASH_PARAM + TXHASH_PARAM + txhash;
-        final TxProxyTO response = getRequest(urlParams, TxProxyTO.class);
+        final TxProxyTO response = getResponse(urlParams, TxProxyTO.class);
         return Optional.ofNullable(response.getResult());
     }
 
@@ -115,7 +115,7 @@ public Optional<TxProxy> tx(long blockNo, long index) throws EtherScanException
 
         final String urlParams = ACT_TX_BY_BLOCKNOINDEX_PARAM + TAG_PARAM + compBlockNo + INDEX_PARAM + "0x"
                 + Long.toHexString(compIndex);
-        final TxProxyTO response = getRequest(urlParams, TxProxyTO.class);
+        final TxProxyTO response = getResponse(urlParams, TxProxyTO.class);
         return Optional.ofNullable(response.getResult());
     }
 
@@ -123,7 +123,7 @@ public Optional<TxProxy> tx(long blockNo, long index) throws EtherScanException
     public int txCount(long blockNo) throws EtherScanException {
         final long compensatedBlockNo = BasicUtils.compensateMinBlock(blockNo);
         final String urlParams = ACT_BLOCKTX_COUNT_PARAM + TAG_PARAM + "0x" + Long.toHexString(compensatedBlockNo);
-        final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
+        final StringProxyTO response = getResponse(urlParams, StringProxyTO.class);
         return BasicUtils.parseHex(response.getResult()).intValue();
     }
 
@@ -132,7 +132,7 @@ public int txSendCount(@NotNull String address) throws EtherScanException {
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_TX_COUNT_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
-        final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
+        final StringProxyTO response = getResponse(urlParams, StringProxyTO.class);
         return BasicUtils.parseHex(response.getResult()).intValue();
     }
 
@@ -165,7 +165,7 @@ public Optional<ReceiptProxy> txReceipt(@NotNull String txhash) throws EtherScan
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_TX_RECEIPT_PARAM + TXHASH_PARAM + txhash;
-        final TxInfoProxyTO response = getRequest(urlParams, TxInfoProxyTO.class);
+        final TxInfoProxyTO response = getResponse(urlParams, TxInfoProxyTO.class);
         return Optional.ofNullable(response.getResult());
     }
 
@@ -177,7 +177,7 @@ public Optional<String> call(@NotNull String address, @NotNull String data) thro
             throw new EtherScanInvalidDataHexException("Data is not hex encoded.");
 
         final String urlParams = ACT_CALL_PARAM + TO_PARAM + address + DATA_PARAM + data + TAG_LAST_PARAM;
-        final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
+        final StringProxyTO response = getResponse(urlParams, StringProxyTO.class);
         return Optional.ofNullable(response.getResult());
     }
 
@@ -187,7 +187,7 @@ public Optional<String> code(@NotNull String address) throws EtherScanException
         BasicUtils.validateAddress(address);
 
         final String urlParams = ACT_CODE_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
-        final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
+        final StringProxyTO response = getResponse(urlParams, StringProxyTO.class);
         return Optional.ofNullable(response.getResult());
     }
 
@@ -198,7 +198,7 @@ public Optional<String> storageAt(@NotNull String address, long position) throws
         final long compPosition = BasicUtils.compensateMinBlock(position);
 
         final String urlParams = ACT_STORAGEAT_PARAM + ADDRESS_PARAM + address + POSITION_PARAM + compPosition + TAG_LAST_PARAM;
-        final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
+        final StringProxyTO response = getResponse(urlParams, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()) || EMPTY_HEX.matcher(response.getResult()).matches())
                 ? Optional.empty()
                 : Optional.of(response.getResult());
@@ -207,7 +207,7 @@ public Optional<String> storageAt(@NotNull String address, long position) throws
     @NotNull
     @Override
     public Wei gasPrice() throws EtherScanException {
-        final StringProxyTO response = getRequest(ACT_GASPRICE_PARAM, StringProxyTO.class);
+        final StringProxyTO response = getResponse(ACT_GASPRICE_PARAM, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
                 ? Wei.ofWei(0)
                 : Wei.ofWei(BasicUtils.parseHex(response.getResult()));
@@ -226,7 +226,7 @@ public Wei gasEstimated(@NotNull String hexData) throws EtherScanException {
             throw new EtherScanInvalidDataHexException("Data is not in hex format.");
 
         final String urlParams = ACT_ESTIMATEGAS_PARAM + DATA_PARAM + hexData + GAS_PARAM + "2000000000000000";
-        final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
+        final StringProxyTO response = getResponse(urlParams, StringProxyTO.class);
         return (BasicUtils.isEmpty(response.getResult()))
                 ? Wei.ofWei(0)
                 : Wei.ofWei(BasicUtils.parseHex(response.getResult()));
diff --git a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
index a2bba16..006017a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/StatisticAPIProvider.java
@@ -21,7 +21,7 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-final class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
+public class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
 
     private static final String ACT_SUPPLY_PARAM = ACT_PREFIX + "ethsupply";
     private static final String ACT_SUPPLY2_PARAM = ACT_PREFIX + "ethsupply2";
@@ -30,18 +30,18 @@ final class StatisticAPIProvider extends BasicProvider implements StatisticAPI {
 
     private static final String CONTRACT_ADDRESS_PARAM = "&contractaddress=";
 
-    StatisticAPIProvider(RequestQueueManager queue,
-                         String baseUrl,
-                         EthHttpClient executor,
-                         Converter converter,
-                         int retry) {
+    public StatisticAPIProvider(RequestQueueManager queue,
+                                String baseUrl,
+                                EthHttpClient executor,
+                                Converter converter,
+                                int retry) {
         super(queue, "stats", baseUrl, executor, converter, retry);
     }
 
     @NotNull
     @Override
     public Wei supply() throws EtherScanException {
-        final StringResponseTO response = getRequest(ACT_SUPPLY_PARAM, StringResponseTO.class);
+        final StringResponseTO response = getResponse(ACT_SUPPLY_PARAM, StringResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
@@ -50,7 +50,7 @@ public Wei supply() throws EtherScanException {
 
     @Override
     public @NotNull EthSupply supplyTotal() throws EtherScanException {
-        final EthSupplyResponseTO response = getRequest(ACT_SUPPLY2_PARAM, EthSupplyResponseTO.class);
+        final EthSupplyResponseTO response = getResponse(ACT_SUPPLY2_PARAM, EthSupplyResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
@@ -63,7 +63,7 @@ public Wei supply(@NotNull String contract) throws EtherScanException {
         BasicUtils.validateAddress(contract);
 
         final String urlParams = ACT_TOKEN_SUPPLY_PARAM + CONTRACT_ADDRESS_PARAM + contract;
-        final StringResponseTO response = getRequest(urlParams, StringResponseTO.class);
+        final StringResponseTO response = getResponse(urlParams, StringResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
@@ -73,7 +73,7 @@ public Wei supply(@NotNull String contract) throws EtherScanException {
     @NotNull
     @Override
     public Price priceLast() throws EtherScanException {
-        final PriceResponseTO response = getRequest(ACT_LASTPRICE_PARAM, PriceResponseTO.class);
+        final PriceResponseTO response = getResponse(ACT_LASTPRICE_PARAM, PriceResponseTO.class);
         if (response.getStatus() != 1)
             throw new EtherScanResponseException(response);
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
index 7374335..61f2484 100644
--- a/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/TransactionAPIProvider.java
@@ -17,18 +17,18 @@
  * @see TransactionAPI
  * @since 28.10.2018
  */
-final class TransactionAPIProvider extends BasicProvider implements TransactionAPI {
+public class TransactionAPIProvider extends BasicProvider implements TransactionAPI {
 
     private static final String ACT_EXEC_STATUS_PARAM = ACT_PREFIX + "getstatus";
     private static final String ACT_RECEIPT_STATUS_PARAM = ACT_PREFIX + "gettxreceiptstatus";
 
     private static final String TXHASH_PARAM = "&txhash=";
 
-    TransactionAPIProvider(RequestQueueManager queue,
-                           String baseUrl,
-                           EthHttpClient executor,
-                           Converter converter,
-                           int retryCount) {
+    public TransactionAPIProvider(RequestQueueManager queue,
+                                  String baseUrl,
+                                  EthHttpClient executor,
+                                  Converter converter,
+                                  int retryCount) {
         super(queue, "transaction", baseUrl, executor, converter, retryCount);
     }
 
@@ -38,7 +38,7 @@ public Optional<Status> statusExec(@NotNull String txhash) throws EtherScanExcep
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_EXEC_STATUS_PARAM + TXHASH_PARAM + txhash;
-        final StatusResponseTO response = getRequest(urlParams, StatusResponseTO.class);
+        final StatusResponseTO response = getResponse(urlParams, StatusResponseTO.class);
         BasicUtils.validateTxResponse(response);
 
         return Optional.ofNullable(response.getResult());
@@ -50,7 +50,7 @@ public Optional<Boolean> statusReceipt(@NotNull String txhash) throws EtherScanE
         BasicUtils.validateTxHash(txhash);
 
         final String urlParams = ACT_RECEIPT_STATUS_PARAM + TXHASH_PARAM + txhash;
-        final ReceiptStatusResponseTO response = getRequest(urlParams, ReceiptStatusResponseTO.class);
+        final ReceiptStatusResponseTO response = getResponse(urlParams, ReceiptStatusResponseTO.class);
         BasicUtils.validateTxResponse(response);
 
         return (response.getResult() == null || BasicUtils.isEmpty(response.getResult().getStatus()))
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionTimeoutException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionTimeoutException.java
new file mode 100644
index 0000000..1b2ff22
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanConnectionTimeoutException.java
@@ -0,0 +1,12 @@
+package io.goodforgod.api.etherscan.error;
+
+/**
+ * @author GoodforGod
+ * @since 12.11.2018
+ */
+public class EtherScanConnectionTimeoutException extends EtherScanConnectionException {
+
+    public EtherScanConnectionTimeoutException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java b/src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java
deleted file mode 100644
index 7734139..0000000
--- a/src/main/java/io/goodforgod/api/etherscan/error/EtherScanTimeoutException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.goodforgod.api.etherscan.error;
-
-/**
- * @author GoodforGod
- * @since 12.11.2018
- */
-public class EtherScanTimeoutException extends EtherScanConnectionException {
-
-    public EtherScanTimeoutException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
index bd01f83..28142b8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/EthHttpClient.java
@@ -17,7 +17,7 @@ public interface EthHttpClient {
      * @param uri as string
      * @return result as string
      */
-    byte[] get(@NotNull URI uri);
+    EthResponse get(@NotNull URI uri);
 
     /**
      * Performs a Http POST request
@@ -26,5 +26,5 @@ public interface EthHttpClient {
      * @param body to post
      * @return result as string
      */
-    byte[] post(@NotNull URI uri, byte[] body);
+    EthResponse post(@NotNull URI uri, byte[] body);
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/EthResponse.java b/src/main/java/io/goodforgod/api/etherscan/http/EthResponse.java
new file mode 100644
index 0000000..20b7d81
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/http/EthResponse.java
@@ -0,0 +1,30 @@
+package io.goodforgod.api.etherscan.http;
+
+import java.util.List;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Anton Kurako (GoodforGod)
+ * 
+ * @since 07.09.2025
+ */
+public interface EthResponse {
+
+    int statusCode();
+
+    @Nullable
+    byte[] body();
+
+    @NotNull
+    Map<String, List<String>> headers();
+
+    static EthResponse of(int statusCode, @Nullable byte[] body) {
+        return new SimpleEthResponse(statusCode, body, null);
+    }
+
+    static EthResponse of(int statusCode, @Nullable byte[] body, @Nullable Map<String, List<String>> headers) {
+        return new SimpleEthResponse(statusCode, body, headers);
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/SimpleEthResponse.java b/src/main/java/io/goodforgod/api/etherscan/http/SimpleEthResponse.java
new file mode 100644
index 0000000..2e9ebf4
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/http/SimpleEthResponse.java
@@ -0,0 +1,64 @@
+package io.goodforgod.api.etherscan.http;
+
+import java.util.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Anton Kurako (GoodforGod)
+ *
+ * @since 07.09.2025
+ */
+class SimpleEthResponse implements EthResponse {
+
+    private final int statusCode;
+    @Nullable
+    private final byte[] body;
+    private final Map<String, List<String>> headers;
+
+    SimpleEthResponse(int statusCode, @Nullable byte[] body, @Nullable Map<String, List<String>> headers) {
+        this.statusCode = statusCode;
+        this.body = body;
+        this.headers = (headers == null)
+                ? Collections.emptyMap()
+                : headers;
+    }
+
+    @Override
+    public int statusCode() {
+        return statusCode;
+    }
+
+    @Nullable
+    @Override
+    public byte[] body() {
+        return body;
+    }
+
+    @Override
+    public @NotNull Map<String, List<String>> headers() {
+        return headers;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        SimpleEthResponse that = (SimpleEthResponse) o;
+        return statusCode == that.statusCode && Arrays.equals(body, that.body) && Objects.equals(headers, that.headers);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(statusCode, headers);
+        result = 31 * result + Arrays.hashCode(body);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "{\"statusCode\": " + statusCode + ", \"headers\": " + headers + ", \"body\": \"" + Arrays.toString(body) + "\"}";
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
new file mode 100644
index 0000000..df7a28b
--- /dev/null
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
@@ -0,0 +1,148 @@
+package io.goodforgod.api.etherscan.http.impl;
+
+import io.goodforgod.api.etherscan.error.EtherScanConnectionException;
+import io.goodforgod.api.etherscan.error.EtherScanConnectionTimeoutException;
+import io.goodforgod.api.etherscan.http.EthHttpClient;
+import io.goodforgod.api.etherscan.http.EthResponse;
+import org.jetbrains.annotations.ApiStatus.Internal;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpConnectTimeoutException;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Anton Kurako (GoodforGod)
+ *
+ * @since 07.09.2025
+ */
+@Internal
+public class JdkEthHttpClient implements EthHttpClient {
+
+    private static final Map<String, String> DEFAULT_HEADERS = new HashMap<>();
+
+    private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(8);
+    private static final Duration DEFAULT_READ_TIMEOUT = Duration.ofMinutes(2);
+
+    static {
+        DEFAULT_HEADERS.put("Accept-Language", "en");
+        DEFAULT_HEADERS.put("Accept-Encoding", "deflate, gzip");
+        DEFAULT_HEADERS.put("User-Agent", "Chrome/68.0.3440.106");
+        DEFAULT_HEADERS.put("Accept-Charset", "UTF-8");
+    }
+
+    private final HttpClient httpClient;
+    private final Duration requestTimeout;
+    private final Map<String, String> headers;
+
+    public JdkEthHttpClient() {
+        this(HttpClient.newBuilder()
+                        .connectTimeout(DEFAULT_CONNECT_TIMEOUT)
+                        .followRedirects(HttpClient.Redirect.NORMAL)
+                        .version(HttpClient.Version.HTTP_2)
+                        .build(),
+                DEFAULT_READ_TIMEOUT,
+                DEFAULT_HEADERS);
+    }
+
+    public JdkEthHttpClient(HttpClient httpClient) {
+        this(httpClient, DEFAULT_READ_TIMEOUT, DEFAULT_HEADERS);
+    }
+
+    public JdkEthHttpClient(HttpClient httpClient, Duration requestTimeout) {
+        this(httpClient, requestTimeout, DEFAULT_HEADERS);
+    }
+
+    public JdkEthHttpClient(HttpClient httpClient, Duration requestTimeout, Map<String, String> headers) {
+        this.httpClient = httpClient;
+        this.requestTimeout = requestTimeout;
+        this.headers = headers;
+    }
+
+    @Override
+    public EthResponse get(@NotNull URI uri) {
+        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
+                .GET()
+                .uri(uri)
+                .timeout(requestTimeout);
+
+        headers.forEach(requestBuilder::header);
+
+        try {
+            HttpResponse<byte[]> response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
+            return new EthResponse() {
+
+                @Override
+                public int statusCode() {
+                    return response.statusCode();
+                }
+
+                @Override
+                public byte[] body() {
+                    return response.body();
+                }
+
+                @Override
+                public @NotNull Map<String, List<String>> headers() {
+                    return response.headers().map();
+                }
+            };
+        } catch (HttpConnectTimeoutException e) {
+            throw new EtherScanConnectionTimeoutException(
+                    "Connection Timeout: Could not establish connection to Etherscan server for "
+                            + httpClient.connectTimeout().orElse(DEFAULT_CONNECT_TIMEOUT) + " millis",
+                    e);
+        } catch (IOException e) {
+            throw new EtherScanConnectionException("Etherscan HTTP server network error occurred: " + e.getMessage(), e);
+        } catch (InterruptedException e) {
+            throw new EtherScanConnectionException("Etherscan HTTP server interrupt exception occurred: " + e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public EthResponse post(@NotNull URI uri, byte[] body) {
+        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
+                .POST(HttpRequest.BodyPublishers.ofByteArray(body))
+                .uri(uri)
+                .timeout(requestTimeout);
+
+        headers.forEach(requestBuilder::header);
+
+        try {
+            HttpResponse<byte[]> response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
+            return new EthResponse() {
+
+                @Override
+                public int statusCode() {
+                    return response.statusCode();
+                }
+
+                @Override
+                public byte[] body() {
+                    return response.body();
+                }
+
+                @Override
+                public @NotNull Map<String, List<String>> headers() {
+                    return response.headers().map();
+                }
+            };
+        } catch (HttpConnectTimeoutException e) {
+            throw new EtherScanConnectionTimeoutException(
+                    "Connection Timeout: Could not establish connection to Etherscan server for "
+                            + httpClient.connectTimeout().orElse(DEFAULT_CONNECT_TIMEOUT) + " millis",
+                    e);
+        } catch (IOException e) {
+            throw new EtherScanConnectionException("Etherscan HTTP server network error occurred: " + e.getMessage(), e);
+        } catch (InterruptedException e) {
+            throw new EtherScanConnectionException("Etherscan HTTP server interrupt exception occurred: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
index b298743..58f4658 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/UrlEthHttpClient.java
@@ -3,20 +3,23 @@
 import static java.net.HttpURLConnection.*;
 
 import io.goodforgod.api.etherscan.error.EtherScanConnectionException;
-import io.goodforgod.api.etherscan.error.EtherScanTimeoutException;
+import io.goodforgod.api.etherscan.error.EtherScanConnectionTimeoutException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
-import java.io.*;
-import java.net.HttpURLConnection;
-import java.net.SocketTimeoutException;
-import java.net.URI;
-import java.net.URL;
+import io.goodforgod.api.etherscan.http.EthResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.*;
 import java.time.Duration;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.InflaterInputStream;
+import org.jetbrains.annotations.ApiStatus.Internal;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Http client implementation
@@ -25,12 +28,13 @@
  * @see EthHttpClient
  * @since 28.10.2018
  */
-public final class UrlEthHttpClient implements EthHttpClient {
+@Internal
+public class UrlEthHttpClient implements EthHttpClient {
 
     private static final Map<String, String> DEFAULT_HEADERS = new HashMap<>();
 
     private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(8);
-    private static final Duration DEFAULT_READ_TIMEOUT = Duration.ZERO;
+    private static final Duration DEFAULT_READ_TIMEOUT = Duration.ofMinutes(2);
 
     static {
         DEFAULT_HEADERS.put("Accept-Language", "en");
@@ -39,6 +43,8 @@ public final class UrlEthHttpClient implements EthHttpClient {
         DEFAULT_HEADERS.put("Accept-Charset", "UTF-8");
     }
 
+    @Nullable
+    private final Proxy proxy;
     private final Map<String, String> headers;
     private final int connectTimeout;
     private final int readTimeout;
@@ -48,11 +54,19 @@ public UrlEthHttpClient() {
     }
 
     public UrlEthHttpClient(Duration connectTimeout) {
-        this(connectTimeout, DEFAULT_READ_TIMEOUT);
+        this(connectTimeout, DEFAULT_READ_TIMEOUT, DEFAULT_HEADERS, null);
     }
 
     public UrlEthHttpClient(Duration connectTimeout, Duration readTimeout) {
-        this(connectTimeout, readTimeout, DEFAULT_HEADERS);
+        this(connectTimeout, readTimeout, DEFAULT_HEADERS, null);
+    }
+
+    public UrlEthHttpClient(Duration connectTimeout, Duration readTimeout, Proxy proxy) {
+        this(connectTimeout, readTimeout, DEFAULT_HEADERS, null);
+    }
+
+    public UrlEthHttpClient(Duration connectTimeout, Duration readTimeout, Map<String, String> headers) {
+        this(connectTimeout, readTimeout, headers, null);
     }
 
     /**
@@ -62,15 +76,19 @@ public UrlEthHttpClient(Duration connectTimeout, Duration readTimeout) {
      */
     public UrlEthHttpClient(Duration connectTimeout,
                             Duration readTimeout,
-                            Map<String, String> headers) {
+                            Map<String, String> headers,
+                            @Nullable Proxy proxy) {
         this.connectTimeout = Math.toIntExact(connectTimeout.toMillis());
         this.readTimeout = Math.toIntExact(readTimeout.toMillis());
         this.headers = Collections.unmodifiableMap(headers);
+        this.proxy = proxy;
     }
 
     private HttpURLConnection buildConnection(URI uri, String method) throws IOException {
         final URL url = uri.toURL();
-        final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        final HttpURLConnection connection = (proxy == null)
+                ? (HttpURLConnection) url.openConnection()
+                : (HttpURLConnection) url.openConnection(proxy);
         connection.setRequestMethod(method);
         connection.setConnectTimeout(connectTimeout);
         connection.setReadTimeout(readTimeout);
@@ -79,7 +97,7 @@ private HttpURLConnection buildConnection(URI uri, String method) throws IOExcep
     }
 
     @Override
-    public byte[] get(@NotNull URI uri) {
+    public EthResponse get(@NotNull URI uri) {
         try {
             final HttpURLConnection connection = buildConnection(uri, "GET");
             final int status = connection.getResponseCode();
@@ -92,17 +110,19 @@ public byte[] get(@NotNull URI uri) {
             }
 
             final byte[] data = readData(connection);
+            EthResponse ethResponse = EthResponse.of(connection.getResponseCode(), data, connection.getHeaderFields());
             connection.disconnect();
-            return data;
+            return ethResponse;
         } catch (SocketTimeoutException e) {
-            throw new EtherScanTimeoutException("Timeout: Could not establish connection for " + connectTimeout + " millis", e);
+            throw new EtherScanConnectionTimeoutException(
+                    "Timeout: Could not establish connection for " + connectTimeout + " millis", e);
         } catch (Exception e) {
             throw new EtherScanConnectionException(e.getMessage(), e);
         }
     }
 
     @Override
-    public byte[] post(@NotNull URI uri, byte[] body) {
+    public EthResponse post(@NotNull URI uri, byte[] body) {
         try {
             final HttpURLConnection connection = buildConnection(uri, "POST");
             final int contentLength = body.length;
@@ -126,10 +146,12 @@ public byte[] post(@NotNull URI uri, byte[] body) {
             }
 
             final byte[] data = readData(connection);
+            EthResponse ethResponse = EthResponse.of(connection.getResponseCode(), data, connection.getHeaderFields());
             connection.disconnect();
-            return data;
+            return ethResponse;
         } catch (SocketTimeoutException e) {
-            throw new EtherScanTimeoutException("Timeout: Could not establish connection for " + connectTimeout + " millis", e);
+            throw new EtherScanConnectionTimeoutException(
+                    "Timeout: Could not establish connection for " + connectTimeout + " millis", e);
         } catch (Exception e) {
             throw new EtherScanConnectionException(e.getMessage(), e);
         }
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java
index 626b4c1..ed81b94 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/impl/FakeRequestQueueManager.java
@@ -8,7 +8,7 @@
  * @author GoodforGod
  * @since 03.11.2018
  */
-public final class FakeRequestQueueManager implements RequestQueueManager {
+public class FakeRequestQueueManager implements RequestQueueManager {
 
     @Override
     public void takeTurn() {
diff --git a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
index 2a3483c..44c6bd5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
+++ b/src/main/java/io/goodforgod/api/etherscan/manager/impl/SemaphoreRequestQueueManager.java
@@ -14,7 +14,7 @@
  * @author GoodforGod
  * @since 30.10.2018
  */
-public final class SemaphoreRequestQueueManager implements RequestQueueManager, AutoCloseable {
+public class SemaphoreRequestQueueManager implements RequestQueueManager, AutoCloseable {
 
     private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
     private final Semaphore semaphore;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
index fbf71be..21b6601 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Abi.java
@@ -64,7 +64,7 @@ public static AbiBuilder builder() {
         return new AbiBuilder();
     }
 
-    public static final class AbiBuilder {
+    public static class AbiBuilder {
 
         private String contractAbi;
         private boolean isVerified;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
index 8de679a..e0fc376 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BaseTx.java
@@ -12,7 +12,7 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-abstract class BaseTx implements Comparable<BaseTx> {
+public abstract class BaseTx implements Comparable<BaseTx> {
 
     long blockNumber;
     String timeStamp;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java
index f3c4d67..f77e5d4 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockTx.java
@@ -8,7 +8,7 @@
  * @author Anton Kurako (GoodforGod)
  * @since 15.05.2023
  */
-abstract class BlockTx extends BaseTx {
+public abstract class BlockTx extends BaseTx {
 
     long nonce;
     String blockHash;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
index 961db7e..058e13b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/BlockUncle.java
@@ -64,7 +64,7 @@ public static UncleBuilder builder() {
             return new UncleBuilder();
         }
 
-        public static final class UncleBuilder {
+        public static class UncleBuilder {
 
             private String miner;
             private BigInteger blockreward;
@@ -138,7 +138,7 @@ public static BlockUncleBuilder builder() {
         return new BlockUncleBuilder();
     }
 
-    public static final class BlockUncleBuilder extends Block.BlockBuilder {
+    public static class BlockUncleBuilder extends Block.BlockBuilder {
 
         private long blockNumber;
         private BigInteger blockReward;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
index 2082883..41e62c5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/ContractCreation.java
@@ -52,7 +52,7 @@ public static ContractCreationBuilder builder() {
         return new ContractCreationBuilder();
     }
 
-    public static final class ContractCreationBuilder {
+    public static class ContractCreationBuilder {
 
         private String contractAddress;
         private String contractCreator;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
index c626069..4dbbce7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/EthSupply.java
@@ -67,7 +67,7 @@ public static EthSupplyBuilder builder() {
         return new EthSupplyBuilder();
     }
 
-    public static final class EthSupplyBuilder {
+    public static class EthSupplyBuilder {
 
         private Wei ethSupply;
         private Wei eth2Staking;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
index 6fe1231..7ee8b50 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
@@ -83,7 +83,7 @@ public static GasOracleBuilder builder() {
         return new GasOracleBuilder();
     }
 
-    public static final class GasOracleBuilder {
+    public static class GasOracleBuilder {
 
         private Long lastBlock;
         private Wei safeGasPrice;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Log.java b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
index d54766c..d29db31 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Log.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Log.java
@@ -155,7 +155,7 @@ public static LogBuilder builder() {
         return new LogBuilder();
     }
 
-    public static final class LogBuilder {
+    public static class LogBuilder {
 
         private Long blockNumber;
         private String address;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Price.java b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
index 403b705..0baa38a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Price.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Price.java
@@ -76,7 +76,7 @@ public static PriceBuilder builder() {
         return new PriceBuilder();
     }
 
-    public static final class PriceBuilder {
+    public static class PriceBuilder {
 
         private BigDecimal ethusd;
         private BigDecimal ethbtc;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Status.java b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
index 41b598a..f651b1f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Status.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Status.java
@@ -53,7 +53,7 @@ public static StatusBuilder builder() {
         return new StatusBuilder();
     }
 
-    public static final class StatusBuilder {
+    public static class StatusBuilder {
 
         private int isError;
         private String errDescription;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
index 0a836d1..8843bd6 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/Tx.java
@@ -59,7 +59,7 @@ public static TxBuilder builder() {
         return new TxBuilder();
     }
 
-    public static final class TxBuilder {
+    public static class TxBuilder {
 
         private long blockNumber;
         private LocalDateTime timeStamp;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
index f0b1ce4..ed8754d 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc1155.java
@@ -82,7 +82,7 @@ public static TxErc1155Builder builder() {
         return new TxErc1155Builder();
     }
 
-    public static final class TxErc1155Builder {
+    public static class TxErc1155Builder {
 
         private long blockNumber;
         private LocalDateTime timeStamp;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
index 1d6080e..57d70cb 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc20.java
@@ -83,7 +83,7 @@ public static TxERC20Builder builder() {
         return new TxERC20Builder();
     }
 
-    public static final class TxERC20Builder {
+    public static class TxERC20Builder {
 
         private long blockNumber;
         private LocalDateTime timeStamp;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
index 1ac49a0..64df779 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxErc721.java
@@ -82,7 +82,7 @@ public static TxERC721Builder builder() {
         return new TxERC721Builder();
     }
 
-    public static final class TxERC721Builder {
+    public static class TxERC721Builder {
 
         private long blockNumber;
         private LocalDateTime timeStamp;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
index 389f456..91c2b27 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/TxInternal.java
@@ -89,7 +89,7 @@ public static TxInternalBuilder builder() {
         return new TxInternalBuilder();
     }
 
-    public static final class TxInternalBuilder {
+    public static class TxInternalBuilder {
 
         private long blockNumber;
         private LocalDateTime timeStamp;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index bee4d64..a16fb21 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -194,7 +194,7 @@ public static BlockProxyBuilder builder() {
         return new BlockProxyBuilder();
     }
 
-    public static final class BlockProxyBuilder {
+    public static class BlockProxyBuilder {
 
         private Long number;
         private String hash;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index d88fd6d..717b2e1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -134,7 +134,7 @@ public static ReceiptProxyBuilder builder() {
         return new ReceiptProxyBuilder();
     }
 
-    public static final class ReceiptProxyBuilder {
+    public static class ReceiptProxyBuilder {
 
         private String root;
         private String from;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index 0a89921..1325cc4 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -156,7 +156,7 @@ public static TxProxyBuilder builder() {
         return new TxProxyBuilder();
     }
 
-    public static final class TxProxyBuilder {
+    public static class TxProxyBuilder {
 
         private String to;
         private String hash;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
index ef57193..2960bfc 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
@@ -4,7 +4,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-abstract class BaseProxyTO {
+public abstract class BaseProxyTO {
 
     private String id;
     private String jsonrpc;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
index 549bd47..f46a4e0 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryBuilderImpl.java
@@ -12,7 +12,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-final class LogQueryBuilderImpl implements LogQuery.Builder {
+public class LogQueryBuilderImpl implements LogQuery.Builder {
 
     static final long MIN_BLOCK = 0;
     static final long MAX_BLOCK = 99999999999999999L;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
index ef66e72..6de9631 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
@@ -12,7 +12,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-final class LogQueryImpl implements LogQuery {
+public class LogQueryImpl implements LogQuery {
 
     /**
      * Final request parameter for api call
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryParams.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryParams.java
index ac77ae8..12fb6d0 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryParams.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryParams.java
@@ -10,7 +10,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-final class LogQueryParams {
+public class LogQueryParams {
 
     private LogQueryParams() {}
 
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
index 7fdd9db..f113a4f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
@@ -14,7 +14,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-public final class LogTopicQuadro implements LogTopicBuilder {
+public class LogTopicQuadro implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
index a736ffa..b35c836 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
@@ -14,7 +14,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-public final class LogTopicSingle implements LogTopicBuilder {
+public class LogTopicSingle implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
index ac9efb8..d888a49 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
@@ -14,7 +14,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-public final class LogTopicTriple implements LogTopicBuilder {
+public class LogTopicTriple implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
index 2ef2bba..4a0218e 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
@@ -14,7 +14,7 @@
  * @author GoodforGod
  * @since 31.10.2018
  */
-public final class LogTopicTuple implements LogTopicBuilder {
+public class LogTopicTuple implements LogTopicBuilder {
 
     private final String address;
     private final long startBlock, endBlock;
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java b/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
index 19fa0a1..8b01b3d 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/response/StringResponseTO.java
@@ -16,7 +16,7 @@ public static StringResponseBuilder builder() {
         return new StringResponseBuilder();
     }
 
-    public static final class StringResponseBuilder {
+    public static class StringResponseBuilder {
 
         private String status;
         private String message;
diff --git a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
index 916d4ab..db98bd4 100644
--- a/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
+++ b/src/main/java/io/goodforgod/api/etherscan/util/BasicUtils.java
@@ -17,7 +17,7 @@
  * @author GoodforGod
  * @since 28.10.2018
  */
-public final class BasicUtils {
+public class BasicUtils {
 
     private BasicUtils() {}
 

From 8dbcc82ccba7d82b711275e8df892916796f98ad Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Sun, 7 Sep 2025 15:11:35 +0300
Subject: [PATCH 63/67] [3.0.0-SNAPSHOT] Cleanup

---
 .../io/goodforgod/api/etherscan/BasicProvider.java  |  3 +--
 .../api/etherscan/http/impl/JdkEthHttpClient.java   | 13 ++++++-------
 2 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 2abb2e0..0ab4f20 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -9,12 +9,11 @@
 import io.goodforgod.api.etherscan.manager.RequestQueueManager;
 import io.goodforgod.api.etherscan.model.response.BaseListResponseTO;
 import io.goodforgod.api.etherscan.model.response.StringResponseTO;
+import io.goodforgod.api.etherscan.util.BasicUtils;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
-
-import io.goodforgod.api.etherscan.util.BasicUtils;
 import org.jetbrains.annotations.ApiStatus.Internal;
 
 /**
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
index df7a28b..eca88d8 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
@@ -4,9 +4,6 @@
 import io.goodforgod.api.etherscan.error.EtherScanConnectionTimeoutException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.http.EthResponse;
-import org.jetbrains.annotations.ApiStatus.Internal;
-import org.jetbrains.annotations.NotNull;
-
 import java.io.IOException;
 import java.net.URI;
 import java.net.http.HttpClient;
@@ -17,6 +14,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.jetbrains.annotations.ApiStatus.Internal;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Anton Kurako (GoodforGod)
@@ -44,10 +43,10 @@ public class JdkEthHttpClient implements EthHttpClient {
 
     public JdkEthHttpClient() {
         this(HttpClient.newBuilder()
-                        .connectTimeout(DEFAULT_CONNECT_TIMEOUT)
-                        .followRedirects(HttpClient.Redirect.NORMAL)
-                        .version(HttpClient.Version.HTTP_2)
-                        .build(),
+                .connectTimeout(DEFAULT_CONNECT_TIMEOUT)
+                .followRedirects(HttpClient.Redirect.NORMAL)
+                .version(HttpClient.Version.HTTP_2)
+                .build(),
                 DEFAULT_READ_TIMEOUT,
                 DEFAULT_HEADERS);
     }

From 260899ba17f32b8fab05d5a477d518e450ee3422 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 8 Sep 2025 00:23:30 +0300
Subject: [PATCH 64/67] [3.0.0-SNAPSHOT] Added JdkEthHttpClient gzip/deflate
 protocol support Added EthScanAPIBuilder key required

---
 .../api/etherscan/BasicProvider.java          |  2 +
 .../api/etherscan/EthScanAPIBuilder.java      | 16 +++----
 .../api/etherscan/EtherScanAPI.java           |  4 +-
 .../etherscan/http/impl/JdkEthHttpClient.java | 44 ++++++++++++++++---
 .../goodforgod/api/etherscan/ApiRunner.java   |  7 ++-
 .../api/etherscan/EtherScanAPITests.java      | 11 ++---
 6 files changed, 59 insertions(+), 25 deletions(-)

diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 0ab4f20..4f809b5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -129,7 +129,9 @@ protected <T> T getResponse(String urlParameters, Class<T> tClass) {
 
     protected <T> T getResponse(String urlParameters, Class<T> tClass, int retryCount) {
         try {
+            System.out.println("URL - " + URI.create(baseUrl + module + urlParameters));
             EthResponse response = getResponse(urlParameters);
+            System.out.println("Response - " + new String(response.body(), StandardCharsets.UTF_8));
             return convert(response.body(), tClass);
         } catch (Exception e) {
             if (retryCount < retryCountLimit) {
diff --git a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
index 12bb9d3..fa8af66 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java
@@ -12,6 +12,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
+import java.util.Objects;
 import java.util.function.Supplier;
 import org.jetbrains.annotations.NotNull;
 
@@ -22,12 +23,11 @@
 public class EthScanAPIBuilder implements EtherScanAPI.Builder {
 
     private static final Supplier<EthHttpClient> DEFAULT_SUPPLIER = JdkEthHttpClient::new;
-    private static final String DEFAULT_KEY = "YourApiKeyToken";
 
     private final Gson gson = new GsonConfiguration().builder().create();
 
     private int retryCountOnLimitReach = 0;
-    private String apiKey = DEFAULT_KEY;
+    private String apiKey;
     private RequestQueueManager queueManager;
     private EthNetwork ethNetwork = EthNetworks.MAINNET;
     private Supplier<EthHttpClient> ethHttpClientSupplier = DEFAULT_SUPPLIER;
@@ -43,6 +43,10 @@ public class EthScanAPIBuilder implements EtherScanAPI.Builder {
         }
     };
 
+    public EthScanAPIBuilder(String apiKey) {
+        this.apiKey = apiKey;
+    }
+
     @NotNull
     @Override
     public EtherScanAPI.Builder withApiKey(@NotNull String apiKey) {
@@ -101,13 +105,7 @@ public EtherScanAPI.Builder withRetryOnRateLimit(int maxRetryCount) {
     @Override
     public @NotNull EtherScanAPI build() {
         RequestQueueManager requestQueueManager;
-        if (queueManager != null) {
-            requestQueueManager = queueManager;
-        } else if (DEFAULT_KEY.equals(apiKey)) {
-            requestQueueManager = RequestQueueManager.anonymous();
-        } else {
-            requestQueueManager = RequestQueueManager.planFree();
-        }
+        requestQueueManager = Objects.requireNonNullElseGet(queueManager, RequestQueueManager::planFree);
 
         return new EtherScanAPIProvider(apiKey, ethNetwork, requestQueueManager, ethHttpClientSupplier.get(),
                 converterSupplier.get(), retryCountOnLimitReach);
diff --git a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
index bae1902..4c703bb 100644
--- a/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
+++ b/src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java
@@ -40,8 +40,8 @@ public interface EtherScanAPI extends AutoCloseable {
     GasTrackerAPI gasTracker();
 
     @NotNull
-    static Builder builder() {
-        return new EthScanAPIBuilder();
+    static Builder builder(@NotNull String key) {
+        return new EthScanAPIBuilder(key);
     }
 
     interface Builder {
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
index eca88d8..fea2680 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
@@ -5,15 +5,17 @@
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.http.EthResponse;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.net.URI;
 import java.net.http.HttpClient;
 import java.net.http.HttpConnectTimeoutException;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import java.time.Duration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.InflaterInputStream;
 import org.jetbrains.annotations.ApiStatus.Internal;
 import org.jetbrains.annotations.NotNull;
 
@@ -75,7 +77,9 @@ public EthResponse get(@NotNull URI uri) {
         headers.forEach(requestBuilder::header);
 
         try {
-            HttpResponse<byte[]> response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
+            HttpResponse<InputStream> response = httpClient.send(requestBuilder.build(),
+                    HttpResponse.BodyHandlers.ofInputStream());
+            byte[] bodyAsBytes = getDeflatedBytes(response);
             return new EthResponse() {
 
                 @Override
@@ -85,7 +89,7 @@ public int statusCode() {
 
                 @Override
                 public byte[] body() {
-                    return response.body();
+                    return bodyAsBytes;
                 }
 
                 @Override
@@ -115,7 +119,9 @@ public EthResponse post(@NotNull URI uri, byte[] body) {
         headers.forEach(requestBuilder::header);
 
         try {
-            HttpResponse<byte[]> response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
+            HttpResponse<InputStream> response = httpClient.send(requestBuilder.build(),
+                    HttpResponse.BodyHandlers.ofInputStream());
+            byte[] bodyAsBytes = getDeflatedBytes(response);
             return new EthResponse() {
 
                 @Override
@@ -125,7 +131,7 @@ public int statusCode() {
 
                 @Override
                 public byte[] body() {
-                    return response.body();
+                    return bodyAsBytes;
                 }
 
                 @Override
@@ -144,4 +150,28 @@ public byte[] body() {
             throw new EtherScanConnectionException("Etherscan HTTP server interrupt exception occurred: " + e.getMessage(), e);
         }
     }
+
+    private static byte[] getDeflatedBytes(HttpResponse<InputStream> response) {
+        try {
+            Optional<String> encoding = response.headers().firstValue("content-encoding");
+            if (encoding.isEmpty()) {
+                try (var is = response.body()) {
+                    return is.readAllBytes();
+                }
+            }
+
+            switch (encoding.get().strip().toLowerCase(Locale.ROOT)) {
+                case "gzip":
+                    return new GZIPInputStream(response.body()).readAllBytes();
+                case "deflate":
+                    return new InflaterInputStream(response.body()).readAllBytes();
+                default:
+                    try (var is = response.body()) {
+                        return is.readAllBytes();
+                    }
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
 }
diff --git a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
index bc4f334..23df478 100644
--- a/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
+++ b/src/test/java/io/goodforgod/api/etherscan/ApiRunner.java
@@ -25,8 +25,7 @@ public class ApiRunner extends Assertions {
                 ? RequestQueueManager.anonymous()
                 : RequestQueueManager.planFree();
 
-        API = EtherScanAPI.builder()
-                .withApiKey(ApiRunner.API_KEY)
+        API = EtherScanAPI.builder(ApiRunner.API_KEY)
                 .withNetwork(EthNetworks.MAINNET)
                 .withQueue(queueManager)
                 .withRetryOnRateLimit(5)
@@ -37,6 +36,10 @@ public static EtherScanAPI getApi() {
         return API;
     }
 
+    public static String getKey() {
+        return API_KEY;
+    }
+
     @AfterAll
     public static void cleanup() throws Exception {
         API.close();
diff --git a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
index 36e23ec..d9e84f0 100644
--- a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
@@ -22,25 +22,26 @@ class EtherScanAPITests extends ApiRunner {
     @Test
     void validKey() {
         String validKey = "YourKey";
-        EtherScanAPI api = EtherScanAPI.builder().withApiKey(validKey).withNetwork(network).build();
+        EtherScanAPI api = EtherScanAPI.builder(validKey).withApiKey(validKey).withNetwork(network).build();
         assertNotNull(api);
     }
 
     @Test
     void emptyKey() {
-        assertThrows(EtherScanKeyException.class, () -> EtherScanAPI.builder().withApiKey("").build());
+        assertThrows(EtherScanKeyException.class, () -> EtherScanAPI.builder("someKey").withApiKey("").build());
     }
 
     @Test
     void blankKey() {
         assertThrows(EtherScanKeyException.class,
-                () -> EtherScanAPI.builder().withApiKey("         ").withNetwork(network).build());
+                () -> EtherScanAPI.builder("someKey").withApiKey("         ").withNetwork(network).build());
     }
 
     @Test
     void noTimeoutOnRead() {
         Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300));
-        EtherScanAPI api = EtherScanAPI.builder().withNetwork(EthNetworks.MAINNET).withHttpClient(supplier).build();
+        EtherScanAPI api = EtherScanAPI.builder(ApiRunner.getKey()).withNetwork(EthNetworks.MAINNET).withHttpClient(supplier)
+                .build();
         Balance balance = api.account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
         assertNotNull(balance);
     }
@@ -67,7 +68,7 @@ void noTimeoutUnlimitedAwait() {
     void timeout() throws InterruptedException {
         TimeUnit.SECONDS.sleep(5);
         Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300), Duration.ofMillis(300));
-        EtherScanAPI api = EtherScanAPI.builder()
+        EtherScanAPI api = EtherScanAPI.builder(ApiRunner.getKey())
                 .withNetwork(() -> URI.create("https://api-unknown.etherscan.io/api"))
                 .withHttpClient(supplier)
                 .build();

From 7ea05262d05a803099e79e4f783b6bd926d9c9c6 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 8 Sep 2025 01:08:49 +0300
Subject: [PATCH 65/67] [3.0.0-SNAPSHOT] Added JdkEthHttpClient gzip/deflate
 protocol support Added EthScanAPIBuilder key required Fixed JdkEthHttpClient
 fallback to UrlEthHttpClient cause content-length works incorrectly Updated
 test and fixed

---
 .github/workflows/master.yml                  | 37 +++++++++++++++++++
 .github/workflows/publish-release.yml         |  4 +-
 .github/workflows/publish-snapshot.yml        |  4 +-
 .github/workflows/pull-request.yml            | 18 +--------
 build.gradle                                  | 10 ++---
 .../etherscan/http/impl/JdkEthHttpClient.java |  9 +++++
 .../api/etherscan/model/GasOracle.java        | 13 +++----
 .../api/etherscan/EtherScanAPITests.java      | 28 --------------
 .../etherscan/account/AccountTxsTests.java    |  4 +-
 .../etherscan/proxy/ProxyBlockApiTests.java   |  1 -
 10 files changed, 62 insertions(+), 66 deletions(-)
 create mode 100644 .github/workflows/master.yml

diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
new file mode 100644
index 0000000..7e82142
--- /dev/null
+++ b/.github/workflows/master.yml
@@ -0,0 +1,37 @@
+name: CI Master
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: 0 0 * * 0
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        java: [ '11', '17' ]
+    name: Master Java ${{ matrix.java }} action
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Set up JDK
+        uses: actions/setup-java@v3
+        with:
+          java-version: ${{ matrix.java }}
+          distribution: 'adopt'
+
+      - name: Build
+        run: './gradlew classes'
+
+      - name: Test
+        run: './gradlew test jacocoTestReport'
+
+      - name: SonarQube
+        if: matrix.java == '17'
+        run: './gradlew sonar --info'
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index 3aa7884..6555593 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -1,4 +1,4 @@
-name: CI Master
+name: Release
 
 on:
   release:
@@ -22,8 +22,6 @@ jobs:
 
       - name: Test
         run: './gradlew test jacocoTestReport'
-        env:
-          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
 
       - name: SonarQube
         run: './gradlew sonar --info'
diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml
index d181a6c..cc95412 100644
--- a/.github/workflows/publish-snapshot.yml
+++ b/.github/workflows/publish-snapshot.yml
@@ -1,4 +1,4 @@
-name: CI Dev
+name: Snapshot
 
 on:
   push:
@@ -32,8 +32,6 @@ jobs:
 
       - name: Test
         run: './gradlew test jacocoTestReport'
-        env:
-          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
 
       - name: Publish Snapshot
         run: './gradlew publish'
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 0b49f50..9da9b35 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -12,7 +12,7 @@ jobs:
     strategy:
       matrix:
         java: [ '11', '17' ]
-    name: Java ${{ matrix.java }} Pull Request setup
+    name: Pull Request Java ${{ matrix.java }} action
 
     steps:
       - uses: actions/checkout@v3
@@ -29,23 +29,7 @@ jobs:
         run: './gradlew classes'
 
       - name: Test
-        if: matrix.java == '11'
         run: './gradlew test jacocoTestReport'
-        env:
-          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_1 }}
-
-      - name: Test
-        if: matrix.java == '17'
-        run: './gradlew test jacocoTestReport'
-        env:
-          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_2 }}
-
-      - name: Test Report
-        if: matrix.java == '17'
-        uses: EnricoMi/publish-unit-test-result-action@v2
-        with:
-          files: |
-            **/test-results/**/*.xml
 
       - name: SonarQube
         if: matrix.java == '17'
diff --git a/build.gradle b/build.gradle
index f946f1d..6fcbb8c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,7 +35,7 @@ test {
     testLogging {
         events("passed", "skipped", "failed")
         exceptionFormat("full")
-        showStandardStreams(false)
+        showStandardStreams(true)
     }
 
     reports {
@@ -71,8 +71,8 @@ nexusPublishing {
         sonatype {
             username = System.getenv("OSS_USERNAME")
             password = System.getenv("OSS_PASSWORD")
-            nexusUrl.set(uri("https://oss.sonatype.org/service/local/"))
-            snapshotRepositoryUrl.set(uri("https://oss.sonatype.org/content/repositories/snapshots/"))
+            nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
+            snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
         }
     }
 }
@@ -110,8 +110,8 @@ publishing {
     }
     repositories {
         maven {
-            def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
-            def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
+            def releasesRepoUrl = "https://ossrh-staging-api.central.sonatype.com/service/local/"
+            def snapshotsRepoUrl = "https://central.sonatype.com/repository/maven-snapshots/"
             url = version.endsWith("SNAPSHOT") ? snapshotsRepoUrl : releasesRepoUrl
             credentials {
                 username System.getenv("OSS_USERNAME")
diff --git a/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
index fea2680..01580ce 100644
--- a/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
+++ b/src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java
@@ -42,6 +42,7 @@ public class JdkEthHttpClient implements EthHttpClient {
     private final HttpClient httpClient;
     private final Duration requestTimeout;
     private final Map<String, String> headers;
+    private final UrlEthHttpClient urlEthHttpClient;
 
     public JdkEthHttpClient() {
         this(HttpClient.newBuilder()
@@ -65,6 +66,7 @@ public JdkEthHttpClient(HttpClient httpClient, Duration requestTimeout, Map<Stri
         this.httpClient = httpClient;
         this.requestTimeout = requestTimeout;
         this.headers = headers;
+        this.urlEthHttpClient = new UrlEthHttpClient(DEFAULT_CONNECT_TIMEOUT, requestTimeout, headers);
     }
 
     @Override
@@ -111,12 +113,19 @@ public byte[] body() {
 
     @Override
     public EthResponse post(@NotNull URI uri, byte[] body) {
+        return urlEthHttpClient.post(uri, body);
+    }
+
+    // content-length somehow is not working properly and can't force user to override
+    // "jdk.httpclient.allowRestrictedHeaders" prop, so will force use UrlEthHttpClient
+    private EthResponse postJdk(@NotNull URI uri, byte[] body) {
         HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                 .POST(HttpRequest.BodyPublishers.ofByteArray(body))
                 .uri(uri)
                 .timeout(requestTimeout);
 
         headers.forEach(requestBuilder::header);
+        requestBuilder.header("Content-Type", "application/json; charset=UTF-8");
 
         try {
             HttpResponse<InputStream> response = httpClient.send(requestBuilder.build(),
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
index 7ee8b50..e7726f9 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/GasOracle.java
@@ -1,7 +1,6 @@
 package io.goodforgod.api.etherscan.model;
 
 import java.math.BigDecimal;
-import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -14,9 +13,9 @@
 public class GasOracle {
 
     private Long LastBlock;
-    private BigInteger SafeGasPrice;
-    private BigInteger ProposeGasPrice;
-    private BigInteger FastGasPrice;
+    private BigDecimal SafeGasPrice;
+    private BigDecimal ProposeGasPrice;
+    private BigDecimal FastGasPrice;
     private BigDecimal suggestBaseFee;
     private String gasUsedRatio;
 
@@ -129,13 +128,13 @@ public GasOracle build() {
             gasOracle.LastBlock = this.lastBlock;
             gasOracle.suggestBaseFee = this.suggestBaseFee;
             if (this.proposeGasPrice != null) {
-                gasOracle.ProposeGasPrice = this.proposeGasPrice.asGwei().toBigInteger();
+                gasOracle.ProposeGasPrice = this.proposeGasPrice.asGwei();
             }
             if (this.safeGasPrice != null) {
-                gasOracle.SafeGasPrice = this.safeGasPrice.asGwei().toBigInteger();
+                gasOracle.SafeGasPrice = this.safeGasPrice.asGwei();
             }
             if (this.fastGasPrice != null) {
-                gasOracle.FastGasPrice = this.fastGasPrice.asGwei().toBigInteger();
+                gasOracle.FastGasPrice = this.fastGasPrice.asGwei();
             }
             if (this.gasUsedRatio != null) {
                 gasOracle.gasUsedRatio = this.gasUsedRatio.stream()
diff --git a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
index d9e84f0..636e752 100644
--- a/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java
@@ -4,7 +4,6 @@
 import io.goodforgod.api.etherscan.error.EtherScanKeyException;
 import io.goodforgod.api.etherscan.http.EthHttpClient;
 import io.goodforgod.api.etherscan.http.impl.UrlEthHttpClient;
-import io.goodforgod.api.etherscan.model.Balance;
 import java.net.URI;
 import java.time.Duration;
 import java.util.concurrent.TimeUnit;
@@ -37,33 +36,6 @@ void blankKey() {
                 () -> EtherScanAPI.builder("someKey").withApiKey("         ").withNetwork(network).build());
     }
 
-    @Test
-    void noTimeoutOnRead() {
-        Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300));
-        EtherScanAPI api = EtherScanAPI.builder(ApiRunner.getKey()).withNetwork(EthNetworks.MAINNET).withHttpClient(supplier)
-                .build();
-        Balance balance = api.account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
-    @Test
-    void noTimeoutOnReadGroli() {
-        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
-    @Test
-    void noTimeoutOnReadTobalala() {
-        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
-    @Test
-    void noTimeoutUnlimitedAwait() {
-        Balance balance = getApi().account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
-        assertNotNull(balance);
-    }
-
     @Test
     void timeout() throws InterruptedException {
         TimeUnit.SECONDS.sleep(5);
diff --git a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
index 653f62a..42e89c4 100644
--- a/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/account/AccountTxsTests.java
@@ -16,7 +16,7 @@ class AccountTxsTests extends ApiRunner {
     void correct() {
         List<Tx> txs = getApi().account().txs("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9");
         assertNotNull(txs);
-        assertEquals(5, txs.size());
+        assertEquals(6, txs.size());
         assertTxs(txs);
         assertNotNull(txs.get(0).getTimeStamp());
         assertNotNull(txs.get(0).getHash());
@@ -39,7 +39,7 @@ void correct() {
     void correctStartBlock() {
         List<Tx> txs = getApi().account().txs("0x9327cb34984c3992ec1EA0eAE98Ccf80A74f95B9", 3892842);
         assertNotNull(txs);
-        assertEquals(4, txs.size());
+        assertEquals(5, txs.size());
         assertTxs(txs);
     }
 
diff --git a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
index 363d5a2..53ed4cd 100644
--- a/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
+++ b/src/test/java/io/goodforgod/api/etherscan/proxy/ProxyBlockApiTests.java
@@ -22,7 +22,6 @@ void correct() {
         assertNotNull(proxy.getStateRoot());
         assertNotNull(proxy.getSize());
         assertNotNull(proxy.getDifficulty());
-        assertNotNull(proxy.getTotalDifficulty());
         assertNotNull(proxy.getTimeStamp());
         assertNotNull(proxy.getMiner());
         assertNotNull(proxy.getNonce());

From 7790bb7484bd36657c8e6a67de87bff941120599 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 8 Sep 2025 01:26:05 +0300
Subject: [PATCH 66/67] [3.0.0-SNAPSHOT] Cleanup

---
 .github/workflows/master.yml                                 | 2 +-
 .github/workflows/pull-request.yml                           | 2 +-
 src/main/java/io/goodforgod/api/etherscan/BasicProvider.java | 2 --
 3 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 7e82142..9892f9c 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -12,7 +12,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        java: [ '11', '17' ]
+        java: [ '11' ]
     name: Master Java ${{ matrix.java }} action
 
     steps:
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 9da9b35..99940ee 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -11,7 +11,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        java: [ '11', '17' ]
+        java: [ '11' ]
     name: Pull Request Java ${{ matrix.java }} action
 
     steps:
diff --git a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
index 4f809b5..0ab4f20 100644
--- a/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
+++ b/src/main/java/io/goodforgod/api/etherscan/BasicProvider.java
@@ -129,9 +129,7 @@ protected <T> T getResponse(String urlParameters, Class<T> tClass) {
 
     protected <T> T getResponse(String urlParameters, Class<T> tClass, int retryCount) {
         try {
-            System.out.println("URL - " + URI.create(baseUrl + module + urlParameters));
             EthResponse response = getResponse(urlParameters);
-            System.out.println("Response - " + new String(response.body(), StandardCharsets.UTF_8));
             return convert(response.body(), tClass);
         } catch (Exception e) {
             if (retryCount < retryCountLimit) {

From 5c69eb92e32d337c2cdeb0d61598b185ee8eefd7 Mon Sep 17 00:00:00 2001
From: Anton Kurako <goodforgod.dev@gmail.com>
Date: Mon, 8 Sep 2025 13:56:50 +0300
Subject: [PATCH 67/67] [3.0.0-SNAPSHOT] Updated CI with key Added more
 toString/equalsHashcode contracts

---
 .github/workflows/master.yml                  |   4 +-
 .github/workflows/publish-release.yml         |   2 +
 .github/workflows/publish-snapshot.yml        |   2 +
 .github/workflows/pull-request.yml            |   4 +-
 README.md                                     |   2 +-
 build.gradle                                  |   2 +-
 .../api/etherscan/model/proxy/BlockProxy.java | 101 ++++++++++--------
 .../etherscan/model/proxy/ReceiptProxy.java   |  81 ++++++++------
 .../api/etherscan/model/proxy/TxProxy.java    |  86 ++++++++-------
 .../model/proxy/utility/BaseProxyTO.java      |  26 +++++
 .../model/proxy/utility/BlockProxyTO.java     |  25 +++++
 .../model/proxy/utility/ErrorProxyTO.java     |  25 +++++
 .../model/proxy/utility/StringProxyTO.java    |  26 +++++
 .../model/proxy/utility/TxInfoProxyTO.java    |  25 +++++
 .../model/proxy/utility/TxProxyTO.java        |  25 +++++
 .../etherscan/model/query/LogQueryImpl.java   |  23 ++++
 .../etherscan/model/query/LogTopicQuadro.java |  40 +++++++
 .../etherscan/model/query/LogTopicSingle.java |  27 +++++
 .../etherscan/model/query/LogTopicTriple.java |  34 ++++++
 .../etherscan/model/query/LogTopicTuple.java  |  30 ++++++
 20 files changed, 472 insertions(+), 118 deletions(-)

diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 9892f9c..32d0d9f 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -28,9 +28,11 @@ jobs:
 
       - name: Test
         run: './gradlew test jacocoTestReport'
+        env:
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
 
       - name: SonarQube
-        if: matrix.java == '17'
+        if: matrix.java == '11'
         run: './gradlew sonar --info'
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index 6555593..ed10cc4 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -22,6 +22,8 @@ jobs:
 
       - name: Test
         run: './gradlew test jacocoTestReport'
+        env:
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_PUBLISH }}
 
       - name: SonarQube
         run: './gradlew sonar --info'
diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml
index cc95412..4a4d958 100644
--- a/.github/workflows/publish-snapshot.yml
+++ b/.github/workflows/publish-snapshot.yml
@@ -32,6 +32,8 @@ jobs:
 
       - name: Test
         run: './gradlew test jacocoTestReport'
+        env:
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY_PUBLISH }}
 
       - name: Publish Snapshot
         run: './gradlew publish'
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 99940ee..c9c6a99 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -30,9 +30,11 @@ jobs:
 
       - name: Test
         run: './gradlew test jacocoTestReport'
+        env:
+          ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
 
       - name: SonarQube
-        if: matrix.java == '17'
+        if: matrix.java == '11'
         run: './gradlew sonar --info'
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/README.md b/README.md
index 160f8e4..c09c885 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Java EtherScan API 
 
-[![Minimum required Java version](https://img.shields.io/badge/Java-1.8%2B-blue?logo=openjdk)](https://openjdk.org/projects/jdk8/)
+[![Minimum required Java version](https://img.shields.io/badge/Java-11%2B-blue?logo=openjdk)](https://openjdk.org/projects/jdk/11/)
 [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.goodforgod/java-etherscan-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.goodforgod/java-etherscan-api)
 [![Java CI](https://github.com/GoodforGod/java-etherscan-api/workflows/CI%20Master/badge.svg)](https://github.com/GoodforGod/java-etherscan-api/actions?query=workflow%3ACI+Master)
 [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GoodforGod_java-etherscan-api&metric=coverage)](https://sonarcloud.io/dashboard?id=GoodforGod_java-etherscan-api)
diff --git a/build.gradle b/build.gradle
index 6fcbb8c..b9be8cd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,7 +35,7 @@ test {
     testLogging {
         events("passed", "skipped", "failed")
         exceptionFormat("full")
-        showStandardStreams(true)
+        showStandardStreams(false)
     }
 
     reports {
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
index a16fb21..b138c14 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/BlockProxy.java
@@ -143,48 +143,6 @@ public List<TxProxy> getTransactions() {
     }
     // </editor-fold>
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (!(o instanceof BlockProxy))
-            return false;
-        BlockProxy that = (BlockProxy) o;
-        return Objects.equals(number, that.number) && Objects.equals(hash, that.hash)
-                && Objects.equals(parentHash, that.parentHash) && Objects.equals(nonce, that.nonce);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(number, hash, parentHash, nonce);
-    }
-
-    @Override
-    public String toString() {
-        return "BlockProxy{" +
-                "number=" + number +
-                ", hash=" + hash +
-                ", parentHash=" + parentHash +
-                ", stateRoot=" + stateRoot +
-                ", size=" + size +
-                ", difficulty=" + difficulty +
-                ", totalDifficulty=" + totalDifficulty +
-                ", timestamp=" + timestamp +
-                ", miner=" + miner +
-                ", nonce=" + nonce +
-                ", extraData=" + extraData +
-                ", logsBloom=" + logsBloom +
-                ", mixHash=" + mixHash +
-                ", gasUsed=" + gasUsed +
-                ", gasLimit=" + gasLimit +
-                ", sha3Uncles=" + sha3Uncles +
-                ", uncles=" + uncles +
-                ", receiptsRoot=" + receiptsRoot +
-                ", transactionsRoot=" + transactionsRoot +
-                ", transactions=" + transactions +
-                '}';
-    }
-
     @Override
     public int compareTo(@NotNull BlockProxy o) {
         return Long.compare(getNumber(), o.getNumber());
@@ -353,4 +311,63 @@ public BlockProxy build() {
             return blockProxy;
         }
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        BlockProxy that = (BlockProxy) o;
+        return Objects.equals(number, that.number) && Objects.equals(_number, that._number) && Objects.equals(hash, that.hash)
+                && Objects.equals(parentHash, that.parentHash) && Objects.equals(stateRoot, that.stateRoot)
+                && Objects.equals(size, that.size) && Objects.equals(_size, that._size)
+                && Objects.equals(difficulty, that.difficulty) && Objects.equals(totalDifficulty, that.totalDifficulty)
+                && Objects.equals(timestamp, that.timestamp) && Objects.equals(_timestamp, that._timestamp)
+                && Objects.equals(miner, that.miner) && Objects.equals(nonce, that.nonce)
+                && Objects.equals(extraData, that.extraData) && Objects.equals(logsBloom, that.logsBloom)
+                && Objects.equals(mixHash, that.mixHash) && Objects.equals(gasUsed, that.gasUsed)
+                && Objects.equals(_gasUsed, that._gasUsed) && Objects.equals(gasLimit, that.gasLimit)
+                && Objects.equals(_gasLimit, that._gasLimit) && Objects.equals(sha3Uncles, that.sha3Uncles)
+                && Objects.equals(uncles, that.uncles) && Objects.equals(receiptsRoot, that.receiptsRoot)
+                && Objects.equals(transactionsRoot, that.transactionsRoot) && Objects.equals(transactions, that.transactions);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(number, number, hash, parentHash, stateRoot, size, size, difficulty, totalDifficulty, timestamp,
+                timestamp, miner, nonce, extraData, logsBloom, mixHash, gasUsed, gasUsed, gasLimit, gasLimit, sha3Uncles, uncles,
+                receiptsRoot, transactionsRoot, transactions);
+    }
+
+    @Override
+    public String toString() {
+        return "BlockProxy{" +
+                "number=" + number +
+                ", number=" + _number +
+                ", hash=" + hash +
+                ", parentHash=" + parentHash +
+                ", stateRoot=" + stateRoot +
+                ", size=" + size +
+                ", size=" + _size +
+                ", difficulty=" + difficulty +
+                ", totalDifficulty=" + totalDifficulty +
+                ", timestamp=" + timestamp +
+                ", timestamp=" + _timestamp +
+                ", miner=" + miner +
+                ", nonce=" + nonce +
+                ", extraData=" + extraData +
+                ", logsBloom=" + logsBloom +
+                ", mixHash=" + mixHash +
+                ", gasUsed=" + gasUsed +
+                ", gasUsed=" + _gasUsed +
+                ", gasLimit=" + gasLimit +
+                ", gasLimit=" + _gasLimit +
+                ", sha3Uncles=" + sha3Uncles +
+                ", uncles=" + uncles +
+                ", receiptsRoot=" + receiptsRoot +
+                ", transactionsRoot=" + transactionsRoot +
+                ", transactions=" + transactions +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
index 717b2e1..6c933c5 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/ReceiptProxy.java
@@ -95,41 +95,6 @@ public String getLogsBloom() {
     }
     // </editor-fold>
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (!(o instanceof ReceiptProxy))
-            return false;
-        ReceiptProxy that = (ReceiptProxy) o;
-        return Objects.equals(blockNumber, that.blockNumber) && Objects.equals(blockHash, that.blockHash)
-                && Objects.equals(transactionHash, that.transactionHash)
-                && Objects.equals(transactionIndex, that.transactionIndex);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(blockNumber, blockHash, transactionHash, transactionIndex);
-    }
-
-    @Override
-    public String toString() {
-        return "ReceiptProxy{" +
-                "root=" + root +
-                ", from=" + from +
-                ", to=" + to +
-                ", blockNumber=" + blockNumber +
-                ", blockHash=" + blockHash +
-                ", transactionHash=" + transactionHash +
-                ", transactionIndex=" + transactionIndex +
-                ", gasUsed=" + gasUsed +
-                ", cumulativeGasUsed=" + cumulativeGasUsed +
-                ", contractAddress=" + contractAddress +
-                ", logs=" + logs +
-                ", logsBloom=" + logsBloom +
-                '}';
-    }
-
     public static ReceiptProxyBuilder builder() {
         return new ReceiptProxyBuilder();
     }
@@ -234,4 +199,50 @@ public ReceiptProxy build() {
             return receiptProxy;
         }
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        ReceiptProxy that = (ReceiptProxy) o;
+        return Objects.equals(root, that.root) && Objects.equals(from, that.from) && Objects.equals(to, that.to)
+                && Objects.equals(blockNumber, that.blockNumber) && Objects.equals(_blockNumber, that._blockNumber)
+                && Objects.equals(blockHash, that.blockHash) && Objects.equals(transactionHash, that.transactionHash)
+                && Objects.equals(transactionIndex, that.transactionIndex)
+                && Objects.equals(_transactionIndex, that._transactionIndex) && Objects.equals(gasUsed, that.gasUsed)
+                && Objects.equals(_gasUsed, that._gasUsed) && Objects.equals(cumulativeGasUsed, that.cumulativeGasUsed)
+                && Objects.equals(_cumulativeGasUsed, that._cumulativeGasUsed)
+                && Objects.equals(contractAddress, that.contractAddress) && Objects.equals(logs, that.logs)
+                && Objects.equals(logsBloom, that.logsBloom);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(root, from, to, blockNumber, blockNumber, blockHash, transactionHash, transactionIndex,
+                transactionIndex, gasUsed, gasUsed, cumulativeGasUsed, cumulativeGasUsed, contractAddress, logs, logsBloom);
+    }
+
+    @Override
+    public String toString() {
+        return "ReceiptProxy{" +
+                "root=" + root + '\'' +
+                ", from=" + from + '\'' +
+                ", to=" + to + '\'' +
+                ", blockNumber=" + blockNumber + '\'' +
+                ", blockNumber=" + _blockNumber +
+                ", blockHash=" + blockHash + '\'' +
+                ", transactionHash=" + transactionHash + '\'' +
+                ", transactionIndex=" + transactionIndex + '\'' +
+                ", transactionIndex=" + _transactionIndex +
+                ", gasUsed=" + gasUsed + '\'' +
+                ", gasUsed=" + _gasUsed +
+                ", cumulativeGasUsed=" + cumulativeGasUsed + '\'' +
+                ", cumulativeGasUsed=" + _cumulativeGasUsed +
+                ", contractAddress=" + contractAddress + '\'' +
+                ", logs=" + logs +
+                ", logsBloom=" + logsBloom + '\'' +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
index 1325cc4..4372dde 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/TxProxy.java
@@ -107,43 +107,6 @@ public Long getBlockNumber() {
     }
     // </editor-fold>
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (!(o instanceof TxProxy))
-            return false;
-        TxProxy txProxy = (TxProxy) o;
-        return Objects.equals(hash, txProxy.hash) && Objects.equals(transactionIndex, txProxy.transactionIndex)
-                && Objects.equals(nonce, txProxy.nonce) && Objects.equals(blockHash, txProxy.blockHash)
-                && Objects.equals(blockNumber, txProxy.blockNumber);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(hash, transactionIndex, nonce, blockHash, blockNumber);
-    }
-
-    @Override
-    public String toString() {
-        return "TxProxy{" +
-                "to=" + to +
-                ", hash=" + hash +
-                ", transactionIndex=" + transactionIndex +
-                ", from=" + from +
-                ", v=" + v +
-                ", input=" + input +
-                ", s=" + s +
-                ", r=" + r +
-                ", nonce=" + nonce +
-                ", value=" + value +
-                ", gas=" + gas +
-                ", gasPrice=" + gasPrice +
-                ", blockHash=" + blockHash +
-                ", blockNumber=" + blockNumber +
-                '}';
-    }
-
     @Override
     public int compareTo(@NotNull TxProxy o) {
         final int firstCompare = Long.compare(getBlockNumber(), o.getBlockNumber());
@@ -271,4 +234,53 @@ public TxProxy build() {
             return txProxy;
         }
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        TxProxy txProxy = (TxProxy) o;
+        return Objects.equals(to, txProxy.to) && Objects.equals(hash, txProxy.hash)
+                && Objects.equals(transactionIndex, txProxy.transactionIndex)
+                && Objects.equals(_transactionIndex, txProxy._transactionIndex) && Objects.equals(from, txProxy.from)
+                && Objects.equals(v, txProxy.v) && Objects.equals(input, txProxy.input) && Objects.equals(s, txProxy.s)
+                && Objects.equals(r, txProxy.r) && Objects.equals(nonce, txProxy.nonce) && Objects.equals(_nonce, txProxy._nonce)
+                && Objects.equals(value, txProxy.value) && Objects.equals(gas, txProxy.gas) && Objects.equals(_gas, txProxy._gas)
+                && Objects.equals(gasPrice, txProxy.gasPrice) && Objects.equals(_gasPrice, txProxy._gasPrice)
+                && Objects.equals(blockHash, txProxy.blockHash) && Objects.equals(blockNumber, txProxy.blockNumber)
+                && Objects.equals(_blockNumber, txProxy._blockNumber);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(to, hash, transactionIndex, transactionIndex, from, v, input, s, r, nonce, nonce, value, gas, gas,
+                gasPrice, gasPrice, blockHash, blockNumber, blockNumber);
+    }
+
+    @Override
+    public String toString() {
+        return "TxProxy{" +
+                "to=" + to + '\'' +
+                ", hash=" + hash + '\'' +
+                ", transactionIndex=" + transactionIndex + '\'' +
+                ", transactionIndex=" + _transactionIndex +
+                ", from=" + from + '\'' +
+                ", v=" + v + '\'' +
+                ", input=" + input + '\'' +
+                ", s=" + s + '\'' +
+                ", r=" + r + '\'' +
+                ", nonce=" + nonce + '\'' +
+                ", nonce=" + _nonce +
+                ", value=" + value + '\'' +
+                ", gas=" + gas + '\'' +
+                ", gas=" + _gas +
+                ", gasPrice=" + gasPrice + '\'' +
+                ", gasPrice=" + _gasPrice +
+                ", blockHash=" + blockHash + '\'' +
+                ", blockNumber=" + blockNumber + '\'' +
+                ", blockNumber=" + _blockNumber +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
index 2960bfc..24588c7 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BaseProxyTO.java
@@ -1,5 +1,7 @@
 package io.goodforgod.api.etherscan.model.proxy.utility;
 
+import java.util.Objects;
+
 /**
  * @author GoodforGod
  * @since 31.10.2018
@@ -21,4 +23,28 @@ public String getJsonrpc() {
     public ErrorProxyTO getError() {
         return error;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        BaseProxyTO that = (BaseProxyTO) o;
+        return Objects.equals(id, that.id) && Objects.equals(jsonrpc, that.jsonrpc) && Objects.equals(error, that.error);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, jsonrpc, error);
+    }
+
+    @Override
+    public String toString() {
+        return "BaseProxyTO{" +
+                "id=" + id +
+                ", jsonrpc=" + jsonrpc +
+                ", error=" + error +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BlockProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BlockProxyTO.java
index cf6c16b..b6bf1c1 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BlockProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/BlockProxyTO.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan.model.proxy.utility;
 
 import io.goodforgod.api.etherscan.model.proxy.BlockProxy;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -13,4 +14,28 @@ public class BlockProxyTO extends BaseProxyTO {
     public BlockProxy getResult() {
         return result;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+        BlockProxyTO that = (BlockProxyTO) o;
+        return Objects.equals(result, that.result);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), result);
+    }
+
+    @Override
+    public String toString() {
+        return "BlockProxyTO{" +
+                "result=" + result +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/ErrorProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/ErrorProxyTO.java
index 9b14cec..5aa1f0a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/ErrorProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/ErrorProxyTO.java
@@ -1,5 +1,7 @@
 package io.goodforgod.api.etherscan.model.proxy.utility;
 
+import java.util.Objects;
+
 /**
  * @author GoodforGod
  * @since 03.11.2018
@@ -16,4 +18,27 @@ public String getMessage() {
     public String getCode() {
         return code;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        ErrorProxyTO that = (ErrorProxyTO) o;
+        return Objects.equals(message, that.message) && Objects.equals(code, that.code);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(message, code);
+    }
+
+    @Override
+    public String toString() {
+        return "ErrorProxyTO{" +
+                "message=" + message +
+                ", code=" + code +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/StringProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/StringProxyTO.java
index 489d87b..7afbf9c 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/StringProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/StringProxyTO.java
@@ -1,5 +1,7 @@
 package io.goodforgod.api.etherscan.model.proxy.utility;
 
+import java.util.Objects;
+
 /**
  * @author GoodforGod
  * @since 31.10.2018
@@ -11,4 +13,28 @@ public class StringProxyTO extends BaseProxyTO {
     public String getResult() {
         return result;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+        StringProxyTO that = (StringProxyTO) o;
+        return Objects.equals(result, that.result);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), result);
+    }
+
+    @Override
+    public String toString() {
+        return "StringProxyTO{" +
+                "result=" + result +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxInfoProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
index 208cdbe..672585b 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxInfoProxyTO.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan.model.proxy.utility;
 
 import io.goodforgod.api.etherscan.model.proxy.ReceiptProxy;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -13,4 +14,28 @@ public class TxInfoProxyTO extends BaseProxyTO {
     public ReceiptProxy getResult() {
         return result;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+        TxInfoProxyTO that = (TxInfoProxyTO) o;
+        return Objects.equals(result, that.result);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), result);
+    }
+
+    @Override
+    public String toString() {
+        return "TxInfoProxyTO{" +
+                "result=" + result +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxProxyTO.java b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxProxyTO.java
index 0c084e7..45b885f 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxProxyTO.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/proxy/utility/TxProxyTO.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan.model.proxy.utility;
 
 import io.goodforgod.api.etherscan.model.proxy.TxProxy;
+import java.util.Objects;
 
 /**
  * @author GoodforGod
@@ -13,4 +14,28 @@ public class TxProxyTO extends BaseProxyTO {
     public TxProxy getResult() {
         return result;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+        TxProxyTO txProxyTO = (TxProxyTO) o;
+        return Objects.equals(result, txProxyTO.result);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), result);
+    }
+
+    @Override
+    public String toString() {
+        return "TxProxyTO{" +
+                "result=" + result +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
index 6de9631..6229c76 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogQueryImpl.java
@@ -1,6 +1,7 @@
 package io.goodforgod.api.etherscan.model.query;
 
 import io.goodforgod.api.etherscan.LogsAPI;
+import java.util.Objects;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -27,4 +28,26 @@ public class LogQueryImpl implements LogQuery {
     public @NotNull String params() {
         return params;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        LogQueryImpl logQuery = (LogQueryImpl) o;
+        return Objects.equals(params, logQuery.params);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(params);
+    }
+
+    @Override
+    public String toString() {
+        return "LogQueryImpl{" +
+                "params=" + params + '\'' +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
index f113a4f..ff7bc8a 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicQuadro.java
@@ -4,6 +4,7 @@
 
 import io.goodforgod.api.etherscan.LogsAPI;
 import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
+import java.util.Objects;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -96,4 +97,43 @@ public LogTopicQuadro setOpTopic1_3(LogOp topic1_3_opr) {
                 + TOPIC_1_3_OPR_PARAM + topic1_2_opr.getOperation()
                 + TOPIC_2_3_OPR_PARAM + topic0_2_opr.getOperation());
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        LogTopicQuadro that = (LogTopicQuadro) o;
+        return startBlock == that.startBlock && endBlock == that.endBlock && Objects.equals(address, that.address)
+                && Objects.equals(topic0, that.topic0) && Objects.equals(topic1, that.topic1)
+                && Objects.equals(topic2, that.topic2) && Objects.equals(topic3, that.topic3) && topic0_1_opr == that.topic0_1_opr
+                && topic1_2_opr == that.topic1_2_opr && topic2_3_opr == that.topic2_3_opr && topic0_2_opr == that.topic0_2_opr
+                && topic0_3_opr == that.topic0_3_opr && topic1_3_opr == that.topic1_3_opr;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(address, startBlock, endBlock, topic0, topic1, topic2, topic3, topic0_1_opr, topic1_2_opr,
+                topic2_3_opr, topic0_2_opr, topic0_3_opr, topic1_3_opr);
+    }
+
+    @Override
+    public String toString() {
+        return "LogTopicQuadro{" +
+                "address=" + address + '\'' +
+                ", startBlock=" + startBlock +
+                ", endBlock=" + endBlock +
+                ", topic0=" + topic0 + '\'' +
+                ", topic1=" + topic1 + '\'' +
+                ", topic2=" + topic2 + '\'' +
+                ", topic3=" + topic3 + '\'' +
+                ", topic0_1_opr=" + topic0_1_opr +
+                ", topic1_2_opr=" + topic1_2_opr +
+                ", topic2_3_opr=" + topic2_3_opr +
+                ", topic0_2_opr=" + topic0_2_opr +
+                ", topic0_3_opr=" + topic0_3_opr +
+                ", topic1_3_opr=" + topic1_3_opr +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
index b35c836..58d7bda 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicSingle.java
@@ -4,6 +4,7 @@
 
 import io.goodforgod.api.etherscan.LogsAPI;
 import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
+import java.util.Objects;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -34,4 +35,30 @@ public class LogTopicSingle implements LogTopicBuilder {
                 + FROM_BLOCK_PARAM + startBlock + TO_BLOCK_PARAM + endBlock
                 + TOPIC_0_PARAM + topic0);
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        LogTopicSingle that = (LogTopicSingle) o;
+        return startBlock == that.startBlock && endBlock == that.endBlock && Objects.equals(address, that.address)
+                && Objects.equals(topic0, that.topic0);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(address, startBlock, endBlock, topic0);
+    }
+
+    @Override
+    public String toString() {
+        return "LogTopicSingle{" +
+                "address=" + address + '\'' +
+                ", startBlock=" + startBlock +
+                ", endBlock=" + endBlock +
+                ", topic0=" + topic0 + '\'' +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
index d888a49..b5a25fe 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTriple.java
@@ -4,6 +4,7 @@
 
 import io.goodforgod.api.etherscan.LogsAPI;
 import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
+import java.util.Objects;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -69,4 +70,37 @@ public LogTopicTriple setOpTopic1_2(LogOp topic1_2_opr) {
                 + TOPIC_1_2_OPR_PARAM + topic1_2_opr.getOperation()
                 + TOPIC_0_2_OPR_PARAM + topic0_2_opr.getOperation());
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        LogTopicTriple that = (LogTopicTriple) o;
+        return startBlock == that.startBlock && endBlock == that.endBlock && Objects.equals(address, that.address)
+                && Objects.equals(topic0, that.topic0) && Objects.equals(topic1, that.topic1)
+                && Objects.equals(topic2, that.topic2) && topic0_1_opr == that.topic0_1_opr && topic1_2_opr == that.topic1_2_opr
+                && topic0_2_opr == that.topic0_2_opr;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(address, startBlock, endBlock, topic0, topic1, topic2, topic0_1_opr, topic1_2_opr, topic0_2_opr);
+    }
+
+    @Override
+    public String toString() {
+        return "LogTopicTriple{" +
+                "address=" + address + '\'' +
+                ", startBlock=" + startBlock +
+                ", endBlock=" + endBlock +
+                ", topic0=" + topic0 + '\'' +
+                ", topic1=" + topic1 + '\'' +
+                ", topic2=" + topic2 + '\'' +
+                ", topic0_1_opr=" + topic0_1_opr +
+                ", topic1_2_opr=" + topic1_2_opr +
+                ", topic0_2_opr=" + topic0_2_opr +
+                '}';
+    }
 }
diff --git a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
index 4a0218e..e396ace 100644
--- a/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
+++ b/src/main/java/io/goodforgod/api/etherscan/model/query/LogTopicTuple.java
@@ -4,6 +4,7 @@
 
 import io.goodforgod.api.etherscan.LogsAPI;
 import io.goodforgod.api.etherscan.error.EtherScanLogQueryException;
+import java.util.Objects;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -50,4 +51,33 @@ public LogTopicTuple setOpTopic0_1(LogOp topic0_1_opr) {
                 + TOPIC_1_PARAM + topic1
                 + TOPIC_0_1_OPR_PARAM + topic0_1_opr.getOperation());
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        LogTopicTuple that = (LogTopicTuple) o;
+        return startBlock == that.startBlock && endBlock == that.endBlock && Objects.equals(address, that.address)
+                && Objects.equals(topic0, that.topic0) && Objects.equals(topic1, that.topic1)
+                && topic0_1_opr == that.topic0_1_opr;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(address, startBlock, endBlock, topic0, topic1, topic0_1_opr);
+    }
+
+    @Override
+    public String toString() {
+        return "LogTopicTuple{" +
+                "address=" + address + '\'' +
+                ", startBlock=" + startBlock +
+                ", endBlock=" + endBlock +
+                ", topic0=" + topic0 + '\'' +
+                ", topic1=" + topic1 + '\'' +
+                ", topic0_1_opr=" + topic0_1_opr +
+                '}';
+    }
 }