Skip to content

Commit 3795b6d

Browse files
committed
HttpExecutor gzip comparison support
EtherScan constructor tests Minor improvements & fixes
1 parent 2af17f0 commit 3795b6d

File tree

8 files changed

+217
-14
lines changed

8 files changed

+217
-14
lines changed

README.md

+88
Original file line numberDiff line numberDiff line change
@@ -1 +1,89 @@
11
# java-etherscan-api
2+
3+
[Etherscan](https://etherscan.io/apis) Java API implementation.
4+
5+
6+
![](https://media.giphy.com/media/1msHfmVdtuwkXww4ZC/giphy.gif)
7+
8+
## Dependency :rocket:
9+
**Maven**
10+
```xml
11+
<dependency>
12+
<groupId>com.github.goodforgod</groupId>
13+
<artifactId>java-etherscan-api</artifactId>
14+
<version>1.0.0</version>
15+
</dependency>
16+
```
17+
18+
**Gradle**
19+
```groovy
20+
dependencies {
21+
compile 'com.github.goodforgod:java-etherscan-api:1.0.0'
22+
}
23+
```
24+
25+
## Content
26+
- [Overall](#overall)
27+
- [API examples](#api-examples)
28+
- [Account](#account-api)
29+
- [Block](#block-api)
30+
- [Contract](#contract-api)
31+
- [Logs](#logs-api)
32+
- [Proxy](#proxy-api)
33+
- [Stats](#stats-api)
34+
- [Transactions](#transaction-api)
35+
- [Version History](#version-history)
36+
37+
## Overall
38+
39+
How all is linked together:
40+
41+
## Api Examples
42+
43+
You can read about all API methods on [Etherscan](https://etherscan.io/apis)
44+
45+
You can you API with you key or without key as well.
46+
```java
47+
EtherScanApi api = new EtherScanApi();
48+
EtherScanApi api = new EtherScanApi("YourApiKey");
49+
```
50+
51+
### Mainnet and Testnets
52+
API support: *MAINNET, ROPSTEN, KOVAN, RINKEBY* networks.
53+
```java
54+
EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
55+
EtherScanApi api = new EtherScanApi("YourApiKey", EthNetwork.KOVAN);
56+
```
57+
58+
### Account Api
59+
**Get Ether Balance for a single Address Example**
60+
```java
61+
EtherScanApi api = new EtherScanApi();
62+
Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
63+
```
64+
65+
### Block Api
66+
67+
### Contract Api
68+
69+
### Logs Api
70+
71+
### Proxy Api
72+
73+
### Stats Api
74+
75+
### Transaction Api
76+
77+
78+
### Token Api
79+
You can read account API [here](https://etherscan.io/apis#accounts)
80+
81+
Token API migrated to account & stats respectfully.
82+
83+
## Version History
84+
85+
**1.0.0** - Initial project with all API functionality.
86+
87+
## License
88+
89+
This project is licensed under the MIT - see the [LICENSE](LICENSE) file for details.

src/main/java/io/api/etherscan/App.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
import io.api.etherscan.core.impl.EtherScanApi;
44
import io.api.etherscan.model.Balance;
5+
import io.api.etherscan.model.EthNetwork;
56

67
/**
78
*
89
*/
910
public class App {
1011
public static void main(String[] args) {
11-
EtherScanApi api = new EtherScanApi();
12+
EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
1213
Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
1314
System.out.println("Test");
1415
}

src/main/java/io/api/etherscan/core/impl/EtherScanApi.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.api.etherscan.core.impl;
22

33
import io.api.etherscan.core.*;
4+
import io.api.etherscan.error.ApiKeyException;
45
import io.api.etherscan.executor.IHttpExecutor;
56
import io.api.etherscan.executor.impl.HttpExecutor;
67
import io.api.etherscan.manager.IQueueManager;
@@ -50,8 +51,8 @@ public EtherScanApi(final String apiKey,
5051
public EtherScanApi(final String apiKey,
5152
final EthNetwork network,
5253
final Supplier<IHttpExecutor> executorSupplier) {
53-
if (BasicUtils.isEmpty(apiKey))
54-
throw new NullPointerException("API key can not be null");
54+
if (BasicUtils.isBlank(apiKey))
55+
throw new ApiKeyException("API key can not be null or empty");
5556

5657
// EtherScan 5request\sec limit support by queue manager
5758
final IQueueManager masterQueue = (apiKey.equals("YourApiKeyToken"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.api.etherscan.error;
2+
3+
/**
4+
* ! NO DESCRIPTION !
5+
*
6+
* @author GoodforGod
7+
* @since 05.11.2018
8+
*/
9+
public class ApiKeyException extends ApiException {
10+
11+
public ApiKeyException(String message) {
12+
super(message);
13+
}
14+
}

src/main/java/io/api/etherscan/executor/impl/HttpExecutor.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.net.URL;
1313
import java.util.HashMap;
1414
import java.util.Map;
15+
import java.util.zip.GZIPInputStream;
1516

1617
import static java.net.HttpURLConnection.HTTP_MOVED_PERM;
1718
import static java.net.HttpURLConnection.HTTP_MOVED_TEMP;
@@ -28,10 +29,11 @@ public class HttpExecutor implements IHttpExecutor {
2829
private static final Map<String, String> DEFAULT_HEADERS = new HashMap<>();
2930

3031
static {
31-
DEFAULT_HEADERS.put("accept-language", "en,ru;q=0.9");
32-
DEFAULT_HEADERS.put("accept-encoding", "gzip, deflate, br");
33-
DEFAULT_HEADERS.put("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Chrome/68.0.3440.106");
34-
DEFAULT_HEADERS.put("content-type", "application/x-www-form-urlencoded");
32+
DEFAULT_HEADERS.put("Accept-Language", "en;q=0.9");
33+
DEFAULT_HEADERS.put("Accept-Encoding", "deflate, gzip");
34+
DEFAULT_HEADERS.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Chrome/68.0.3440.106");
35+
DEFAULT_HEADERS.put("Content-Type", "application/x-www-form-urlencoded");
36+
DEFAULT_HEADERS.put("Accept-Charset", "UTF-8");
3537
}
3638

3739
private final Map<String, String> headers;
@@ -113,7 +115,7 @@ public String post(final String urlAsString, final String dataToPost) {
113115

114116
private String readData(final HttpURLConnection connection) throws IOException {
115117
final StringBuilder content = new StringBuilder();
116-
try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
118+
try (BufferedReader in = new BufferedReader(getStreamReader(connection))) {
117119
String inputLine;
118120
while ((inputLine = in.readLine()) != null)
119121
content.append(inputLine);
@@ -123,4 +125,10 @@ private String readData(final HttpURLConnection connection) throws IOException {
123125

124126
return content.toString();
125127
}
128+
129+
private InputStreamReader getStreamReader(final HttpURLConnection connection) throws IOException {
130+
return ("gzip".equals(connection.getContentEncoding()))
131+
? new InputStreamReader(new GZIPInputStream(connection.getInputStream()), "utf-8")
132+
: new InputStreamReader(connection.getInputStream(), "utf-8");
133+
}
126134
}

src/main/java/io/api/etherscan/util/BasicUtils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import java.util.regex.Pattern;
1313

1414
/**
15-
* ! NO DESCRIPTION !
15+
* Basic utils for library
1616
*
1717
* @author GoodforGod
1818
* @since 28.10.2018
@@ -30,7 +30,7 @@ public static boolean isEmpty(String value) {
3030
return value == null || value.isEmpty();
3131
}
3232

33-
public static boolean isBlack(String value) {
33+
public static boolean isBlank(String value) {
3434
return value == null || value.isEmpty() || value.trim().isEmpty();
3535
}
3636

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.api.etherscan;
2+
3+
import io.api.etherscan.core.impl.EtherScanApi;
4+
import io.api.etherscan.error.ApiKeyException;
5+
import io.api.etherscan.model.EthNetwork;
6+
import org.junit.Assert;
7+
import org.junit.Test;
8+
9+
/**
10+
* ! NO DESCRIPTION !
11+
*
12+
* @author GoodforGod
13+
* @since 05.11.2018
14+
*/
15+
public class EtherScanApiTest extends Assert {
16+
17+
private EthNetwork network = EthNetwork.KOVAN;
18+
private String validKey = "YourKey";
19+
20+
@Test
21+
public void validKey() {
22+
EtherScanApi api = new EtherScanApi(validKey, network);
23+
assertNotNull(api);
24+
}
25+
26+
@Test(expected = ApiKeyException.class)
27+
public void emptyKey() {
28+
String emptyKey = "";
29+
EtherScanApi api = new EtherScanApi(emptyKey, network);
30+
}
31+
32+
@Test(expected = ApiKeyException.class)
33+
public void blankKey() {
34+
String blankKey = " ";
35+
EtherScanApi api = new EtherScanApi(blankKey, network);
36+
}
37+
38+
@Test
39+
public void nullNetwork() {
40+
EtherScanApi api = new EtherScanApi(validKey, null);
41+
assertNotNull(api);
42+
}
43+
}

src/test/java/io/api/etherscan/account/AccountBalanceTest.java

+52-4
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,70 @@
33
import io.api.etherscan.core.impl.EtherScanApi;
44
import io.api.etherscan.error.InvalidAddressException;
55
import io.api.etherscan.model.Balance;
6+
import io.api.etherscan.model.EthNetwork;
67
import org.junit.Assert;
78
import org.junit.Test;
9+
import org.junit.runner.RunWith;
10+
import org.junit.runners.Parameterized;
11+
import org.junit.runners.Parameterized.Parameters;
12+
13+
import java.util.Arrays;
14+
import java.util.Collection;
815

916
/**
1017
* ! NO DESCRIPTION !
1118
*
1219
* @author GoodforGod
1320
* @since 03.11.2018
1421
*/
22+
@RunWith(Parameterized.class)
1523
public class AccountBalanceTest extends Assert {
1624

17-
private final EtherScanApi api = new EtherScanApi();
25+
private EtherScanApi api;
26+
private String addressCorrect;
27+
private String addressInvalid;
28+
private String addressNoResponse;
29+
30+
public AccountBalanceTest(EtherScanApi api, String addressCorrect, String addressInvalid, String addressNoResponse) {
31+
this.api = api;
32+
this.addressCorrect = addressCorrect;
33+
this.addressInvalid = addressInvalid;
34+
this.addressNoResponse = addressNoResponse;
35+
}
36+
37+
@Parameters
38+
public static Collection data() {
39+
return Arrays.asList(new Object[][]{
40+
{
41+
new EtherScanApi(),
42+
"0x8d4426f94e42f721C7116E81d6688cd935cB3b4F",
43+
"8d4426f94e42f721C7116E81d6688cd935cB3b4F",
44+
"0x1d4426f94e42f721C7116E81d6688cd935cB3b4F"
45+
},
46+
{
47+
new EtherScanApi(EthNetwork.ROPSTEN),
48+
"0xddbd2b932c763ba5b1b7ae3b362eac3e8d40121a",
49+
"xddbd2b932c763ba5b1b7ae3b362eac3e8d40121a",
50+
"0x1dbd2b932c763ba5b1b7ae3b362eac3e8d40121a"
51+
},
52+
{
53+
new EtherScanApi(EthNetwork.RINKEBY),
54+
"0xddbd2b932c763ba5b1b7ae3b362eac3e8d40121a",
55+
"xddbd2b932c763ba5b1b7ae3b362eac3e8d40121a",
56+
"0x1dbd2b932c763ba5b1b7ae3b362eac3e8d40121a"
57+
},
58+
{
59+
new EtherScanApi(EthNetwork.KOVAN),
60+
"0xB9F36EE9df7E2A24B61b1738F4127BFDe8bA1A87",
61+
"xB9F36EE9df7E2A24B61b1738F4127BFDe8bA1A87",
62+
"0xB1F36EE9df7E2A24B61b1738F4127BFDe8bA1A87"
63+
},
64+
});
65+
}
1866

1967
@Test
2068
public void correct() {
21-
Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
69+
Balance balance = api.account().balance(addressCorrect);
2270
assertNotNull(balance);
2371
assertNotNull(balance.getWei());
2472
assertNotNull(balance.getMwei());
@@ -31,12 +79,12 @@ public void correct() {
3179

3280
@Test(expected = InvalidAddressException.class)
3381
public void invalidParamWithError() {
34-
Balance balance = api.account().balance("8d4426f94e42f721C7116E81d6688cd935cB3b4F");
82+
Balance balance = api.account().balance(addressInvalid);
3583
}
3684

3785
@Test
3886
public void correctParamWithEmptyExpectedResult() {
39-
Balance balance = api.account().balance("0x8d4426f94e42f722C7116E81d6688cd935cB3b4F");
87+
Balance balance = api.account().balance(addressNoResponse);
4088
assertNotNull(balance);
4189
assertNotNull(balance.getWei());
4290
assertNotNull(balance.getAddress());

0 commit comments

Comments
 (0)