diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 03c2e11..613a39e 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -4,12 +4,10 @@ on:
push:
branches:
- master
- schedule:
- - cron: "0 12 1 * *"
pull_request:
branches:
- - master
- - dev
+ - master
+ - dev
jobs:
build:
@@ -20,21 +18,26 @@ jobs:
name: Java ${{ matrix.java }} setup
steps:
- - uses: actions/checkout@v1
- - name: Set up JDK
- uses: actions/setup-java@v1
-
- with:
- java-version: ${{ matrix.java }}
-
- - name: Build with Gradle
- run: ./gradlew build jacocoTestReport
- env:
- API_KEY: ${{ secrets.API_KEY }}
-
- - name: Analyze with SonarQube
- run: ./gradlew sonarqube
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- API_KEY: ${{ secrets.API_KEY }}
+ - uses: actions/checkout@v1
+ - name: Set up JDK
+ uses: actions/setup-java@v1
+
+ with:
+ java-version: ${{ matrix.java }}
+
+ - name: Build
+ run: ./gradlew classes
+
+ - name: Codestyle
+ run: ./gradlew spotlessCheck
+
+ - name: Test
+ run: ./gradlew test jacocoTestReport
+ env:
+ API_KEY: ${{ secrets.API_KEY }}
+
+ - name: SonarQube
+ run: ./gradlew sonarqube
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/README.md b/README.md
index 352952b..cd88aaa 100644
--- a/README.md
+++ b/README.md
@@ -11,22 +11,23 @@
Library supports all available EtherScan *API* calls for all available *Ethereum Networks* for *etherscan.io*
## Dependency :rocket:
+
+**Gradle**
+```groovy
+dependencies {
+ compile "com.github.goodforgod:java-etherscan-api:1.1.1"
+}
+```
+
**Maven**
```xml
com.github.goodforgod
java-etherscan-api
- 1.1.0
+ 1.1.1
```
-**Gradle**
-```groovy
-dependencies {
- compile 'com.github.goodforgod:java-etherscan-api:1.1.0'
-}
-```
-
## Content
- [Ethereum Networks](#mainnet-and-testnets)
- [Custom HttpClient](#custom-httpclient)
@@ -42,6 +43,7 @@ dependencies {
- [Version History](#version-history)
## Mainnet and Testnets
+
API support Ethereum: *[MAINNET](https://etherscan.io),
[ROPSTEN](https://ropsten.etherscan.io),
[KOVAN](https://kovan.etherscan.io),
@@ -88,14 +90,18 @@ EtherScanApi api = new EtherScanApi("YourApiKey");
Below are examples for each API category.
### Account Api
+
**Get Ether Balance for a single Address**
+
```java
EtherScanApi api = new EtherScanApi();
Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
```
### Block Api
+
**Get uncles block for block height**
+
```java
EtherScanApi api = new EtherScanApi();
Optional uncles = api.block().uncles(200000);
@@ -109,7 +115,9 @@ Abi abi = api.contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413
```
### Logs Api
+
**Get event logs for single topic**
+
```java
EtherScanApi api = new EtherScanApi();
LogQuery query = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
@@ -119,6 +127,7 @@ List 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)
@@ -134,47 +143,45 @@ List logs = api.logs().logs(query);
```
### Proxy Api
+
**Get tx detailds with proxy endpoint**
+
```java
EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
Optional tx = api.proxy().tx("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
```
**Get block info with proxy endpoint**
+
```java
EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
Optional block = api.proxy().block(15215);
```
### Stats Api
+
**Statistic about last price**
+
```java
EtherScanApi api = new EtherScanApi();
Price price = api.stats().lastPrice();
```
### Transaction Api
+
**Request receipt status for tx**
+
```java
EtherScanApi api = new EtherScanApi();
Optional status = api.txs().receiptStatus("0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
```
### Token Api
+
You can read about token API [here](https://etherscan.io/apis#tokens)
Token API methods migrated to [Account](#account-api) & [Stats](#stats-api) respectfully.
-## Version History
-
-**1.1.0** - Improved error handling, QueueManager improved, Gradle 6.7 instead of Maven, GitHub CI, Sonarcloud analyzer, dependencies updated.
-
-**1.0.2** - Minor http client improvements.
-
-**1.0.1** - Gorli & TOBALABA networks support.
-
-**1.0.0** - Initial project with all API functionality, for all available networks, with tests coverage for all cases.
-
## License
This project licensed under the MIT - see the [LICENSE](LICENSE) file for details.
diff --git a/build.gradle b/build.gradle
index 638baf3..0e3f321 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,27 +1,26 @@
plugins {
- id 'jacoco'
- id 'java-library'
- id 'maven-publish'
+ id "jacoco"
+ id "java-library"
+ id "maven-publish"
- id 'org.sonarqube' version '3.1.1'
- id 'com.diffplug.spotless' version '5.11.0'
+ id "org.sonarqube" version "3.3"
+ id "com.diffplug.spotless" version "5.14.3"
}
repositories {
mavenLocal()
mavenCentral()
- jcenter()
}
group = groupId
version = artifactVersion
-sourceCompatibility = 1.8
-targetCompatibility = 1.8
+sourceCompatibility = JavaVersion.VERSION_1_8
+targetCompatibility = JavaVersion.VERSION_1_8
spotless {
java {
- encoding 'UTF-8'
+ encoding "UTF-8"
removeUnusedImports()
eclipse().configFile "${projectDir}/config/codestyle.xml"
}
@@ -29,43 +28,30 @@ spotless {
sonarqube {
properties {
- property 'sonar.host.url', 'https://sonarcloud.io'
- property 'sonar.organization', 'goodforgod'
- property 'sonar.projectKey', 'GoodforGod_java-etherscan-api'
+ property "sonar.host.url", "https://sonarcloud.io"
+ property "sonar.organization", "goodforgod"
+ property "sonar.projectKey", "GoodforGod_java-etherscan-api"
}
}
dependencies {
- implementation 'org.jetbrains:annotations:20.1.0'
- implementation 'com.google.code.gson:gson:2.8.6'
+ implementation "org.jetbrains:annotations:22.0.0"
+ implementation "com.google.code.gson:gson:2.8.8"
- testImplementation 'junit:junit:4.13.1'
+ testImplementation "junit:junit:4.13.1"
}
test {
- failFast = true
-
useJUnit()
testLogging {
- events "passed", "skipped", "failed"
- exceptionFormat "full"
+ events("passed", "skipped", "failed")
+ exceptionFormat("full")
}
-}
-tasks.withType(JavaCompile) {
- options.encoding = 'UTF-8'
- options.incremental = true
- options.fork = true
-}
-
-tasks.withType(Test) {
- reports.html.enabled = false
- reports.junitXml.enabled = false
-}
-
-java {
- withJavadocJar()
- withSourcesJar()
+ reports {
+ html.enabled(false)
+ junitXml.enabled(false)
+ }
}
publishing {
@@ -74,27 +60,27 @@ publishing {
from components.java
pom {
- name = 'Java Etherscan API'
- url = 'https://github.com/GoodforGod/java-etherscan-api'
- description = 'Library is a wrapper for EtherScan API.'
+ name = "Java Etherscan API"
+ url = "https://github.com/GoodforGod/java-etherscan-api"
+ description = "Library is a wrapper for EtherScan API."
license {
- name = 'MIT License'
- url = 'https://github.com/GoodforGod/java-etherscan-api/blob/master/LICENSE'
- distribution = 'repo'
+ name = "MIT License"
+ url = "https://github.com/GoodforGod/java-etherscan-api/blob/master/LICENSE"
+ distribution = "repo"
}
developer {
- id = 'GoodforGod'
- name = 'Anton Kurako'
- email = 'goodforgod.dev@gmail.com'
- url = 'https://github.com/GoodforGod'
+ id = "GoodforGod"
+ name = "Anton Kurako"
+ email = "goodforgod.dev@gmail.com"
+ url = "https://github.com/GoodforGod"
}
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/java-etherscan-api.git"
+ developerConnection = "scm:git:ssh://GoodforGod/java-etherscan-api.git"
+ url = "https://github.com/GoodforGod/java-etherscan-api/tree/master"
}
}
}
@@ -103,7 +89,7 @@ publishing {
maven {
def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
- url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
+ url = version.endsWith("SNAPSHOT") ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username System.getenv("OSS_USERNAME")
password System.getenv("OSS_PASSWORD")
@@ -112,6 +98,17 @@ publishing {
}
}
+java {
+ withJavadocJar()
+ withSourcesJar()
+}
+
+tasks.withType(JavaCompile) {
+ options.encoding("UTF-8")
+ options.incremental(true)
+ options.fork = true
+}
+
check.dependsOn jacocoTestReport
jacocoTestReport {
reports {
@@ -120,16 +117,16 @@ jacocoTestReport {
}
}
+javadoc {
+ options.encoding = "UTF-8"
+ if (JavaVersion.current().isJava9Compatible()) {
+ options.addBooleanOption("html5", true)
+ }
+}
+
if (project.hasProperty("signing.keyId")) {
- apply plugin: 'signing'
+ apply plugin: "signing"
signing {
sign publishing.publications.mavenJava
}
}
-
-javadoc {
- options.encoding = "UTF-8"
- if (JavaVersion.current().isJava9Compatible()) {
- options.addBooleanOption('html5', true)
- }
-}
\ No newline at end of file
diff --git a/config/codestyle.xml b/config/codestyle.xml
index 0c19beb..a90c4f5 100644
--- a/config/codestyle.xml
+++ b/config/codestyle.xml
@@ -74,7 +74,7 @@
-
+
diff --git a/gradle.properties b/gradle.properties
index 1fa1ad4..e4aacfe 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,6 @@
groupId=com.github.goodforgod
artifactId=java-etherscan-api
-artifactVersion=1.1.0
+artifactVersion=1.1.1
buildNumber=1
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c..7454180 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index be52383..ffed3a2 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-6.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0..744e882 100755
--- a/gradlew
+++ b/gradlew
@@ -72,7 +72,7 @@ case "`uname`" in
Darwin* )
darwin=true
;;
- MINGW* )
+ MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
diff --git a/src/main/java/io/api/etherscan/core/IAccountApi.java b/src/main/java/io/api/etherscan/core/IAccountApi.java
index 6eda869..642f289 100644
--- a/src/main/java/io/api/etherscan/core/IAccountApi.java
+++ b/src/main/java/io/api/etherscan/core/IAccountApi.java
@@ -36,8 +36,8 @@ public interface IAccountApi {
TokenBalance balance(String address, String contract) throws ApiException;
/**
- * Maximum 20 address for single batch request If address MORE THAN 20, then
- * there will be more than 1 request performed
+ * Maximum 20 address for single batch request If address MORE THAN 20, then there will be more than
+ * 1 request performed
*
* @param addresses addresses to get balances for
* @return list of balances
diff --git a/src/main/java/io/api/etherscan/core/ILogsApi.java b/src/main/java/io/api/etherscan/core/ILogsApi.java
index dc7d8d8..37c5eac 100644
--- a/src/main/java/io/api/etherscan/core/ILogsApi.java
+++ b/src/main/java/io/api/etherscan/core/ILogsApi.java
@@ -16,8 +16,7 @@
public interface ILogsApi {
/**
- * alternative to the native eth_getLogs Read at EtherScan API description for
- * full info!
+ * alternative to the native eth_getLogs Read at EtherScan API description for full info!
*
* @param query build log query
* @return logs according to query
diff --git a/src/main/java/io/api/etherscan/core/IProxyApi.java b/src/main/java/io/api/etherscan/core/IProxyApi.java
index 58a70ed..e57f6ec 100644
--- a/src/main/java/io/api/etherscan/core/IProxyApi.java
+++ b/src/main/java/io/api/etherscan/core/IProxyApi.java
@@ -36,8 +36,7 @@ public interface IProxyApi {
Optional block(long blockNo) throws ApiException;
/**
- * Returns information about a uncle by block number
- * eth_getUncleByBlockNumberAndIndex
+ * Returns information about a uncle by block number eth_getUncleByBlockNumberAndIndex
*
* @param blockNo block number from 0 to last
* @param index uncle block index
@@ -59,8 +58,8 @@ public interface IProxyApi {
Optional tx(String txhash) throws ApiException;
/**
- * Returns information about a transaction by block number and transaction index
- * position eth_getTransactionByBlockNumberAndIndex
+ * Returns information about a transaction by block number and transaction index position
+ * eth_getTransactionByBlockNumberAndIndex
*
* @param blockNo block number from 0 to last
* @param index tx index in block
@@ -71,8 +70,8 @@ public interface IProxyApi {
Optional tx(long blockNo, long index) throws ApiException;
/**
- * Returns the number of transactions in a block from a block matching the given
- * block number eth_getBlockTransactionCountByNumber
+ * Returns the number of transactions in a block from a block matching the given block number
+ * eth_getBlockTransactionCountByNumber
*
* @param blockNo block number from 0 to last
* @return transaction amount in block
@@ -81,8 +80,7 @@ public interface IProxyApi {
int txCount(long blockNo) throws ApiException;
/**
- * Returns the number of transactions sent from an address
- * eth_getTransactionCount
+ * Returns the number of transactions sent from an address eth_getTransactionCount
*
* @param address eth address
* @return transactions send amount from address
@@ -91,8 +89,8 @@ public interface IProxyApi {
int txSendCount(String address) throws ApiException;
/**
- * Creates new message call transaction or a contract creation for signed
- * transactions eth_sendRawTransaction
+ * Creates new message call transaction or a contract creation for signed transactions
+ * eth_sendRawTransaction
*
* @param hexEncodedTx encoded hex data to send
* @return optional string response
@@ -102,8 +100,7 @@ public interface IProxyApi {
Optional txSendRaw(String hexEncodedTx) throws ApiException;
/**
- * Returns the receipt of a transaction by transaction hash
- * eth_getTransactionReceipt
+ * Returns the receipt of a transaction by transaction hash eth_getTransactionReceipt
*
* @param txhash transaction hash
* @return optional tx receipt
@@ -113,8 +110,8 @@ public interface IProxyApi {
Optional txReceipt(String txhash) throws ApiException;
/**
- * Executes a new message call immediately without creating a transaction on the
- * block chain eth_call
+ * Executes a new message call immediately without creating a transaction on the block chain
+ * eth_call
*
* @param address to call
* @param data data to call address
@@ -135,8 +132,7 @@ public interface IProxyApi {
Optional code(String address) throws ApiException;
/**
- * (**experimental) Returns the value from a storage position at a given address
- * eth_getStorageAt
+ * (**experimental) Returns the value from a storage position at a given address eth_getStorageAt
*
* @param address to get storage
* @param position storage position
@@ -156,9 +152,8 @@ public interface IProxyApi {
BigInteger gasPrice() throws ApiException;
/**
- * Makes a call or transaction, which won't be added to the blockchain and
- * returns the used gas, which can be used for estimating the used gas
- * eth_estimateGas
+ * Makes a call or transaction, which won't be added to the blockchain and returns the used gas,
+ * which can be used for estimating the used gas eth_estimateGas
*
* @param hexData data to calc gas usage for
* @return estimated gas usage
diff --git a/src/main/java/io/api/etherscan/core/ITransactionApi.java b/src/main/java/io/api/etherscan/core/ITransactionApi.java
index 51c108c..f545c2d 100644
--- a/src/main/java/io/api/etherscan/core/ITransactionApi.java
+++ b/src/main/java/io/api/etherscan/core/ITransactionApi.java
@@ -15,8 +15,7 @@
public interface ITransactionApi {
/**
- * Check Contract Execution Status (if there was an error during contract
- * execution)
+ * Check Contract Execution Status (if there was an error during contract execution)
*
* @param txhash transaction hash
* @return optional status result
@@ -26,8 +25,7 @@ public interface ITransactionApi {
Optional execStatus(String txhash) throws ApiException;
/**
- * Check Transaction Receipt Status (Only applicable for Post Byzantium fork
- * transactions)
+ * 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
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 8cd5d46..ba5dd83 100644
--- a/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
+++ b/src/main/java/io/api/etherscan/core/impl/EtherScanApi.java
@@ -20,12 +20,13 @@
* @author GoodforGod
* @since 28.10.2018
*/
-public class EtherScanApi {
+public class EtherScanApi implements AutoCloseable {
private static final Supplier 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;
@@ -87,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;
+ this.queueManager = queue;
this.account = new AccountApiProvider(queue, baseUrl, executor);
this.block = new BlockApiProvider(queue, baseUrl, executor);
this.contract = new ContractApiProvider(queue, baseUrl, executor);
@@ -130,4 +132,9 @@ public IProxyApi proxy() {
public IStatisticApi stats() {
return stats;
}
+
+ @Override
+ public void close() throws Exception {
+ queueManager.close();
+ }
}
diff --git a/src/main/java/io/api/etherscan/manager/IQueueManager.java b/src/main/java/io/api/etherscan/manager/IQueueManager.java
index 3a65240..98a3172 100644
--- a/src/main/java/io/api/etherscan/manager/IQueueManager.java
+++ b/src/main/java/io/api/etherscan/manager/IQueueManager.java
@@ -1,13 +1,13 @@
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
+ * 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 {
+public interface IQueueManager extends AutoCloseable {
/**
* Waits in queue for chance to take turn
diff --git a/src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java b/src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java
index e797f8b..620244c 100644
--- a/src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java
+++ b/src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java
@@ -15,4 +15,9 @@ public void takeTurn() {
// no limit or await provided for fake impl so rate limit exception will be
// thrown if too many calls
}
+
+ @Override
+ public void close() {
+ // do nothing
+ }
}
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 517883c..80f7c51 100644
--- a/src/main/java/io/api/etherscan/manager/impl/QueueManager.java
+++ b/src/main/java/io/api/etherscan/manager/impl/QueueManager.java
@@ -12,29 +12,53 @@
* @author GoodforGod
* @since 30.10.2018
*/
-public class QueueManager implements IQueueManager {
+public class QueueManager implements IQueueManager, AutoCloseable {
public static final QueueManager DEFAULT_KEY_QUEUE = new QueueManager(1, 7);
- public static final QueueManager PERSONAL_KEY_QUEUE = new QueueManager(2, 1);
+ 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.semaphore = new Semaphore(size);
- Executors.newSingleThreadScheduledExecutor()
- .scheduleAtFixedRate(releaseLocks(size), delayInSec, queueResetTimeInSec, TimeUnit.SECONDS);
+ 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() {
- semaphore.acquireUninterruptibly();
+ 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/Log.java b/src/main/java/io/api/etherscan/model/Log.java
index 4649d6b..36d126b 100644
--- a/src/main/java/io/api/etherscan/model/Log.java
+++ b/src/main/java/io/api/etherscan/model/Log.java
@@ -68,11 +68,10 @@ 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 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
+ * @return milliseconds between Unix epoch and `timeStamp`. If field is empty or null, returns null
*/
public Long getTimeStampAsMillis() {
if (BasicUtils.isEmpty(timeStamp)) {
diff --git a/src/test/java/io/api/ApiRunner.java b/src/test/java/io/api/ApiRunner.java
index 6f608d8..5ccdf83 100644
--- a/src/test/java/io/api/ApiRunner.java
+++ b/src/test/java/io/api/ApiRunner.java
@@ -3,6 +3,7 @@
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;
public class ApiRunner extends Assert {
@@ -11,26 +12,23 @@ public class ApiRunner extends Assert {
private static final EtherScanApi apiRopsten;
private static final EtherScanApi apiRinkeby;
private static final EtherScanApi apiKovan;
- private static final String key;
+ private static final String apiKey;
static {
- final String apiKey = System.getenv("API_KEY");
- key = (apiKey == null || apiKey.isEmpty())
+ final String key = System.getenv("API_KEY");
+ apiKey = (key == null || key.isEmpty())
? EtherScanApi.DEFAULT_KEY
- : apiKey;
+ : key;
- final QueueManager queue = key.equals(EtherScanApi.DEFAULT_KEY)
- ? QueueManager.DEFAULT_KEY_QUEUE
- : new QueueManager(1, 2);
-
- api = new EtherScanApi(key, EthNetwork.MAINNET, queue);
- apiRopsten = new EtherScanApi(key, EthNetwork.ROPSTEN, queue);
- apiRinkeby = new EtherScanApi(key, EthNetwork.RINKEBY, queue);
- apiKovan = new EtherScanApi(key, EthNetwork.KOVAN, queue);
+ final QueueManager queueManager = 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 getKey() {
- return key;
+ public static String getApiKey() {
+ return apiKey;
}
public static EtherScanApi getApi() {
@@ -48,4 +46,12 @@ public static EtherScanApi getApiRinkeby() {
public static EtherScanApi getApiKovan() {
return apiKovan;
}
+
+ @AfterClass
+ 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
index 5071a68..be49435 100644
--- a/src/test/java/io/api/etherscan/EtherScanApiTest.java
+++ b/src/test/java/io/api/etherscan/EtherScanApiTest.java
@@ -79,7 +79,7 @@ public void noTimeoutUnlimitedAwait() {
public void timeout() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
Supplier supplier = () -> new HttpExecutor(300, 300);
- EtherScanApi api = new EtherScanApi(getKey(), EthNetwork.KOVAN, supplier);
+ EtherScanApi api = new EtherScanApi(getApiKey(), EthNetwork.KOVAN, supplier);
List blocks = api.account().minedBlocks("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D");
assertNotNull(blocks);
}
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
index 181a68d..5d3884d 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java
@@ -1,6 +1,9 @@
package io.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 org.junit.Test;
@@ -14,9 +17,16 @@
*/
public class ProxyBlockApiTest extends ApiRunner {
+ private final EtherScanApi api;
+
+ public ProxyBlockApiTest() {
+ final QueueManager queueManager = new QueueManager(1, 5100L, 5100L, 0);
+ this.api = new EtherScanApi(getApiKey(), EthNetwork.MAINNET, queueManager);
+ }
+
@Test
public void correct() {
- Optional block = getApi().proxy().block(5120);
+ Optional block = api.proxy().block(5120);
assertTrue(block.isPresent());
BlockProxy proxy = block.get();
assertNotNull(proxy.getHash());
@@ -49,13 +59,13 @@ public void correct() {
@Test
public void correctParamWithEmptyExpectedResult() {
- Optional block = getApi().proxy().block(99999999999L);
+ Optional block = api.proxy().block(99999999999L);
assertFalse(block.isPresent());
}
@Test
public void correctParamNegativeNo() {
- Optional block = getApi().proxy().block(-1);
+ Optional block = api.proxy().block(-1);
assertTrue(block.isPresent());
assertNotNull(block.get().getHash());
}
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
index c90850c..07d26bd 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java
@@ -41,6 +41,6 @@ public void correctParamWithEmptyExpectedResult() {
Optional call = getApi().proxy().call("0xAEEF16DB4855E25702F8237E8f403FddcaF931C0",
"0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724");
assertTrue(call.isPresent());
- assertFalse(BasicUtils.isNotHex(call.get()));
+ assertFalse(call.get(), BasicUtils.isNotHex(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 3120503..9e4910c 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java
@@ -19,18 +19,18 @@ public class ProxyCodeApiTest extends ApiRunner {
public void correct() {
Optional call = getApi().proxy().code("0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c");
assertTrue(call.isPresent());
- assertFalse(BasicUtils.isNotHex(call.get()));
+ assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
}
@Test(expected = InvalidAddressException.class)
public void invalidParamWithError() {
- Optional call = getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c");
+ getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c");
}
@Test
public void correctParamWithEmptyExpectedResult() {
Optional call = getApi().proxy().code("0xf15e354c5edc8efed9b59ee9f67a80845ade7d0c");
assertTrue(call.isPresent());
- assertFalse(BasicUtils.isNotHex(call.get()));
+ assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
}
}
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
index fbfcf80..ecd7dca 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java
@@ -24,12 +24,12 @@ public void correct() {
@Test(expected = InvalidAddressException.class)
public void invalidParamWithError() {
- Optional call = getApi().proxy().storageAt("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0);
+ getApi().proxy().storageAt("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0);
}
@Test
public void correctParamWithEmptyExpectedResult() {
- Optional call = getApi().proxy().storageAt("0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 100);
+ final Optional call = getApi().proxy().storageAt("0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 10000);
assertFalse(call.isPresent());
}
}
diff --git a/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java b/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
index 6a0778c..b81926f 100644
--- a/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
+++ b/src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java
@@ -32,12 +32,12 @@ public void invalidParamWithError() {
@Test
public void correctParamWithEmptyExpectedResultBlockNoExist() {
int count = getApi().proxy().txCount(99999999999L);
- assertEquals(0, count);
+ assertNotEquals(1, count);
}
@Test
public void correctParamWithEmptyExpectedResult() {
int count = getApi().proxy().txSendCount("0x1e03d9cce9d60f3e9f2597e13cd4c54c55330cfd");
- assertEquals(0, count);
+ assertNotEquals(1, count);
}
}