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 01/55] [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 02/55] 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 03/55] 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 04/55] 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 05/55] 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 06/55] 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 07/55] [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 08/55] [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 09/55] [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 10/55] [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 11/55] [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 12/55] [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 13/55] [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 14/55] [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 15/55] [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 16/55] [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 17/55] [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 18/55] [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 19/55] [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 20/55] [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 21/55] [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 22/55] [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 23/55] [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 24/55] [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 25/55] [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 26/55] [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 27/55] [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 28/55] [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 29/55] [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 30/55] [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 31/55] [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 32/55] [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 33/55] [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 34/55] [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 35/55] [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 36/55] [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 37/55] [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 38/55] [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 39/55] [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 40/55] [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 41/55] [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 42/55] [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 43/55] [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 44/55] 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 45/55] 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 46/55] 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 47/55] 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 48/55] [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 49/55] [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 50/55] [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 51/55] [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 52/55] [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 53/55] [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 54/55] [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 55/55] [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");
 ```