From 81283a29b70d6848785ff420ac2a610e40a0fae5 Mon Sep 17 00:00:00 2001
From: Tokenview <40224239+Tokenview@users.noreply.github.com>
Date: Sat, 6 Mar 2021 15:01:25 +0800
Subject: [PATCH] Add files via upload
---
LICENSE | 21 +
README.md | 28 ++
api-demo.iml | 92 +++++
api-java-sdk/api-java-sdk.iml | 93 +++++
api-java-sdk/pom.xml | 173 ++++++++
.../com/tokenview/api/client/APIClient.java | 86 ++++
.../tokenview/api/client/APICredentials.java | 30 ++
.../tokenview/api/client/APIHttpClient.java | 90 +++++
.../com/tokenview/api/client/APIRetrofit.java | 29 ++
.../com/tokenview/api/client/ApiHttp.java | 38 ++
.../api/config/APIConfiguration.java | 126 ++++++
.../tokenview/api/constant/APIConstants.java | 83 ++++
.../com/tokenview/api/enums/CharsetEnum.java | 24 ++
.../tokenview/api/enums/ContentTypeEnum.java | 26 ++
.../com/tokenview/api/enums/I18nEnum.java | 24 ++
.../com/tokenview/api/enums/ResultCode.java | 111 ++++++
.../tokenview/api/exception/APIException.java | 31 ++
.../com/tokenview/api/result/HttpResult.java | 70 ++++
.../api/service/base/BaseService.java | 25 ++
.../api/service/base/Impl/BaseAPI.java | 29 ++
.../service/base/Impl/BaseServiceImpl.java | 47 +++
.../api/service/wallet/WalletService.java | 16 +
.../api/service/wallet/impl/WalletAPI.java | 20 +
.../wallet/impl/WalletServiceImpl.java | 36 ++
.../tokenview/api/test/base/BaseAPITest.java | 99 +++++
.../tokenview/api/test/base/BaseConfig.java | 29 ++
.../api/test/services/ServicesAPITest.java | 11 +
.../api/test/services/ServicesConfig.java | 30 ++
.../api/test/wallet/WalletAPITest.java | 187 +++++++++
.../api/test/wallet/WalletConfig.java | 29 ++
pom.xml | 17 +
sign-java-sdk/pom.xml | 210 ++++++++++
sign-java-sdk/sign-java-sdk.iml | 91 +++++
.../java/com/tokenview/bean/WalletBean.java | 67 ++++
.../java/com/tokenview/enums/Version.java | 15 +
.../java/com/tokenview/sign/btc/BTCSign.java | 59 +++
.../java/com/tokenview/sign/eth/ETHSign.java | 59 +++
.../com/tokenview/utils/BTCWalletUtil.java | 304 ++++++++++++++
.../java/com/tokenview/utils/HexUtil.java | 80 ++++
.../com/tokenview/utils/HttpClientUtils.java | 370 ++++++++++++++++++
.../java/com/tokenview/utils/HttpUtil.java | 55 +++
.../com/tokenview/sign/test/BTCSignTest.java | 76 ++++
.../com/tokenview/sign/test/ETHSignTest.java | 51 +++
43 files changed, 3187 insertions(+)
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 api-demo.iml
create mode 100644 api-java-sdk/api-java-sdk.iml
create mode 100644 api-java-sdk/pom.xml
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/client/APIClient.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/client/APICredentials.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/client/APIHttpClient.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/client/APIRetrofit.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/client/ApiHttp.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/config/APIConfiguration.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/constant/APIConstants.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/enums/CharsetEnum.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/enums/ContentTypeEnum.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/enums/I18nEnum.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/enums/ResultCode.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/exception/APIException.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/result/HttpResult.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/service/base/BaseService.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseAPI.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseServiceImpl.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/service/wallet/WalletService.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletAPI.java
create mode 100644 api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletServiceImpl.java
create mode 100644 api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseAPITest.java
create mode 100644 api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseConfig.java
create mode 100644 api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesAPITest.java
create mode 100644 api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesConfig.java
create mode 100644 api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletAPITest.java
create mode 100644 api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletConfig.java
create mode 100644 pom.xml
create mode 100644 sign-java-sdk/pom.xml
create mode 100644 sign-java-sdk/sign-java-sdk.iml
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/bean/WalletBean.java
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/enums/Version.java
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/sign/btc/BTCSign.java
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/sign/eth/ETHSign.java
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/utils/BTCWalletUtil.java
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/utils/HexUtil.java
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/utils/HttpClientUtils.java
create mode 100644 sign-java-sdk/src/main/java/com/tokenview/utils/HttpUtil.java
create mode 100644 sign-java-sdk/src/test/java/com/tokenview/sign/test/BTCSignTest.java
create mode 100644 sign-java-sdk/src/test/java/com/tokenview/sign/test/ETHSignTest.java
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..10bc648
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 tokenview-hub
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..45547d1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+The Tokenview api-demo Project
+===
+* Tokenview signature and api program implementation in Java.
+
+Features
+---
+* 120+ blockchains ,100B+ transactions ,20B+ addresses ,coin markets ,statistical information are supported
+* Demo code are mainly used for wallet app now,private key is kept by the developer to prevent leakage during transmission
+* Main crypto currency offline signature is supported
+* Transaction-broadcasting is supported
+* Fully Java ready ,with definition files and full Java source and Springboot2.0
+* MIT License (including ALL dependencies) ;completely open source to do with as you please
+
+Launch your application
+---
+* Get apikey here :https://services.tokenview.com
+* Download api-demo project and check how the tokenview API is called in the test class of this project ,take it as a prototype extension, modify it into the project you want, package it and add it to your application project
+* Check postman document and start your application :https://documenter.getpostman.com/view/5728777/RzZ6HfX2
+
+Documentation
+---
+* Official site :https://services.tokenview.com
+* Browser site :https://tokenview.com
+* Postman document :https://documenter.getpostman.com/view/5728777/RzZ6HfX2
+
+License
+---
+* MIT License (including all dependencies).
diff --git a/api-demo.iml b/api-demo.iml
new file mode 100644
index 0000000..666f4ed
--- /dev/null
+++ b/api-demo.iml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-java-sdk/api-java-sdk.iml b/api-java-sdk/api-java-sdk.iml
new file mode 100644
index 0000000..1d56643
--- /dev/null
+++ b/api-java-sdk/api-java-sdk.iml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-java-sdk/pom.xml b/api-java-sdk/pom.xml
new file mode 100644
index 0000000..1ade63b
--- /dev/null
+++ b/api-java-sdk/pom.xml
@@ -0,0 +1,173 @@
+
+
+
+ api-demo
+ com.tokenview
+ 1.0.0
+
+ 4.0.0
+
+ com.tokenview
+ api-java-sdk
+ 1.0.0
+
+
+
+ com.tokenview
+ sign-java-sdk
+ 1.0.0
+
+
+ io.netty
+ netty-all
+ 4.1.36.Final
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.10.0
+
+
+ com.squareup.retrofit2
+ retrofit
+ 2.3.0
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.8.0-beta2
+
+
+ org.springframework
+ spring-context
+ 5.1.5.RELEASE
+
+
+ com.squareup.retrofit2
+ converter-scalars
+ 2.3.0
+
+
+ com.squareup.retrofit2
+ converter-gson
+ 2.3.0
+
+
+ com.squareup.retrofit2
+ adapter-rxjava
+ 2.3.0
+
+
+ org.apache.commons
+ commons-lang3
+ 3.7
+
+
+ commons-collections
+ commons-collections
+ 3.2.2
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+
+
+ com.google.guava
+ guava
+ 27.1-jre
+
+
+ commons-codec
+ commons-codec
+ 1.12
+
+
+ org.apache.commons
+ commons-compress
+ 1.18
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.5
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.9.3
+
+
+ commons-collections
+ commons-collections
+ 3.2.1
+
+
+ commons-lang
+ commons-lang
+ 2.6
+
+
+ commons-logging
+ commons-logging
+ 1.1.1
+
+
+ net.sf.ezmorph
+ ezmorph
+ 1.0.6
+
+
+ net.sf.json-lib
+ json-lib
+ 2.2.3
+ jdk15
+
+
+ org.springframework
+ spring-web
+ 5.0.9.RELEASE
+ test
+
+
+ jstl
+ jstl
+ 1.2
+ test
+
+
+ com.alibaba
+ fastjson
+ 1.2.12
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.8
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/client/APIClient.java b/api-java-sdk/src/main/java/com/tokenview/api/client/APIClient.java
new file mode 100644
index 0000000..7a545a7
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/client/APIClient.java
@@ -0,0 +1,86 @@
+package com.tokenview.api.client;
+
+import com.alibaba.fastjson.JSON;
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.constant.APIConstants;
+import com.tokenview.api.exception.APIException;
+import com.tokenview.api.result.HttpResult;
+import okhttp3.OkHttpClient;
+import org.apache.commons.lang.StringUtils;
+import retrofit2.Call;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import java.io.IOException;
+
+
+/**
+ * TokenView API Client
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2021/1/20 11:13
+ */
+public class APIClient {
+
+ private final APIConfiguration config;
+ private final APICredentials credentials;
+ private final OkHttpClient client;
+ private final Retrofit retrofit;
+ private final ApiHttp apiHttp;
+ /**
+ * Initialize the apis client
+ */
+ public APIClient(final APIConfiguration config) {
+ if (config == null || StringUtils.isEmpty(config.getEndpoint())) {
+ throw new RuntimeException("The APIClient params can't be empty.");
+ }
+ this.config = config;
+ this.credentials = new APICredentials(config);
+ this.client = new APIHttpClient(config, this.credentials).client();
+ this.retrofit = new APIRetrofit(config, this.client).retrofit();
+ this.apiHttp = new ApiHttp(config, this.client);
+ }
+
+ /**
+ * Initialize the retrofit operation service
+ */
+ public T createService(final Class service) {
+ return this.retrofit.create(service);
+ }
+
+ public ApiHttp getApiHttp() {
+ return this.apiHttp;
+ }
+
+ /**
+ * Synchronous send request
+ */
+ //解析
+ public T executeSync(final Call call){
+ try {
+
+ final Response response = call.execute();
+
+ //获取状态码
+ final int status = response.code();
+ //获取错误信息
+ final String message = new StringBuilder().append(response.code()).append(" / ").append(response.message()).toString();
+ //响应成功
+ if (response.isSuccessful()) {
+ return response.body();
+ } else if (APIConstants.resultStatusArray.contains(status)) {
+ final HttpResult result = JSON.parseObject(new String(response.errorBody().bytes()), HttpResult.class);
+ if(result.getCode() == 0 && result.getMessage() == null){
+ throw new APIException(result.getErrorCode(),result.getErrorMessage());
+ }else{
+ throw new APIException(result.getCode(), result.getMessage());
+ }
+ } else {
+ throw new APIException(message);
+ }
+ } catch (final IOException e) {
+ throw new APIException("APIClient executeSync exception.", e);
+ }
+ }
+
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/client/APICredentials.java b/api-java-sdk/src/main/java/com/tokenview/api/client/APICredentials.java
new file mode 100644
index 0000000..6968538
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/client/APICredentials.java
@@ -0,0 +1,30 @@
+package com.tokenview.api.client;
+
+import com.tokenview.api.config.APIConfiguration;
+
+/**
+ * API Credentials
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2021/1/18 12:24
+ */
+public class APICredentials {
+ public String getApiKey() {
+ return apiKey;
+ }
+
+ public void setApiKey(String apiKey) {
+ this.apiKey = apiKey;
+ }
+
+ /**
+ * The user's secret key provided by TokenView.
+ */
+ private String apiKey;
+
+ public APICredentials(APIConfiguration config) {
+ super();
+ this.apiKey = config.getApiKey();
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/client/APIHttpClient.java b/api-java-sdk/src/main/java/com/tokenview/api/client/APIHttpClient.java
new file mode 100644
index 0000000..6a182c2
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/client/APIHttpClient.java
@@ -0,0 +1,90 @@
+package com.tokenview.api.client;
+
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.constant.APIConstants;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okio.Buffer;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+public class APIHttpClient {
+ private final APIConfiguration config;
+ private final APICredentials credentials;
+
+
+ public APIHttpClient(final APIConfiguration config, final APICredentials credentials) {
+ this.config = config;
+ this.credentials = credentials;
+ }
+
+ public OkHttpClient client() {
+ final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
+ clientBuilder.connectTimeout(this.config.getConnectTimeout(), TimeUnit.SECONDS);
+ clientBuilder.readTimeout(this.config.getReadTimeout(), TimeUnit.SECONDS);
+ clientBuilder.writeTimeout(this.config.getWriteTimeout(), TimeUnit.SECONDS);
+ clientBuilder.retryOnConnectionFailure(this.config.isRetryOnConnectionFailure());
+// clientBuilder.addInterceptor((Interceptor.Chain chain) -> {
+// final Request.Builder requestBuilder = chain.request().newBuilder();
+// final String timestamp = DateUtils.getUnixTime();
+// //打印首行时间戳
+//// System.out.println("时间戳timestamp={" + timestamp + "}");
+//// 设置模拟盘请求头
+//// String simulated = "1";
+// requestBuilder.headers(this.headers(chain.request(), timestamp));
+// final Request request = requestBuilder.build();
+// if (this.config.isPrint()) {
+// this.printRequest(request, timestamp);
+// }
+// return chain.proceed(request);
+// });
+ return clientBuilder.build();
+ }
+
+ //返回请求路径url
+ private String url(final Request request) {
+ return request.url().toString();
+ }
+ //将请求方法转变为大写,并返回
+ private String method(final Request request) {
+ return request.method().toUpperCase();
+ }
+ //返回请求路径
+ private String requestPath(final Request request) {
+ String url = this.url(request);
+ url = url.replace(this.config.getEndpoint(), APIConstants.EMPTY);
+ String requestPath = url;
+ if (requestPath.contains(APIConstants.QUESTION)) {
+ requestPath = requestPath.substring(0, url.lastIndexOf(APIConstants.QUESTION));
+ }
+ if(this.config.getEndpoint().endsWith(APIConstants.SLASH)){
+ requestPath = APIConstants.SLASH + requestPath;
+ }
+ return requestPath;
+ }
+
+ private String queryString(final Request request) {
+ final String url = this.url(request);
+ request.body();
+ //请求参数为空字符串
+ String queryString = APIConstants.EMPTY;
+ //如果URL中包含?即存在参数的拼接
+ if (url.contains(APIConstants.QUESTION)) {
+ queryString = url.substring(url.lastIndexOf(APIConstants.QUESTION) + 1);
+ }
+ return queryString;
+ }
+
+ private String body(final Request request) throws IOException {
+ final RequestBody requestBody = request.body();
+ String body = APIConstants.EMPTY;
+ if (requestBody != null) {
+ final Buffer buffer = new Buffer();
+ requestBody.writeTo(buffer);
+ body = buffer.readString(APIConstants.UTF_8);
+ }
+ return body;
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/client/APIRetrofit.java b/api-java-sdk/src/main/java/com/tokenview/api/client/APIRetrofit.java
new file mode 100644
index 0000000..d5adc33
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/client/APIRetrofit.java
@@ -0,0 +1,29 @@
+package com.tokenview.api.client;
+
+
+import com.tokenview.api.config.APIConfiguration;
+import okhttp3.OkHttpClient;
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+import retrofit2.converter.scalars.ScalarsConverterFactory;
+
+public class APIRetrofit {
+ private APIConfiguration config;
+ private OkHttpClient client;
+
+ public APIRetrofit(APIConfiguration config, OkHttpClient client) {
+ this.config = config;
+ this.client = client;
+ }
+
+ public Retrofit retrofit() {
+ Retrofit.Builder builder = new Retrofit.Builder();
+ builder.client(this.client);
+ builder.addConverterFactory(ScalarsConverterFactory.create());
+ builder.addConverterFactory(GsonConverterFactory.create());
+ builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
+ builder.baseUrl(this.config.getEndpoint());
+ return builder.build();
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/client/ApiHttp.java b/api-java-sdk/src/main/java/com/tokenview/api/client/ApiHttp.java
new file mode 100644
index 0000000..0a7b85f
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/client/ApiHttp.java
@@ -0,0 +1,38 @@
+package com.tokenview.api.client;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.constant.APIConstants;
+import com.tokenview.api.exception.APIException;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Date;
+
+public class ApiHttp {
+ private OkHttpClient client;
+ private APIConfiguration config;
+
+ static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+
+ public ApiHttp(APIConfiguration config, OkHttpClient client) {
+ this.config = config;
+ this.client = client;
+ }
+
+ private void printResponse(int status, String message, String body, boolean responseIsNotNull) {
+ StringBuilder responseInfo = new StringBuilder();
+ responseInfo.append("\n\tResponse").append("(").append(new Date()).append("):");
+ if (responseIsNotNull) {
+ responseInfo.append("\n\t\t").append("Status: ").append(status);
+ responseInfo.append("\n\t\t").append("Message: ").append(message);
+ responseInfo.append("\n\t\t").append("Response Body: ").append(body);
+ } else {
+ responseInfo.append("\n\t\t").append("\n\tRequest Error: response is null");
+ }
+ }
+
+ public String url(String url) {
+ return new StringBuilder(this.config.getEndpoint()).append(url).toString();
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/config/APIConfiguration.java b/api-java-sdk/src/main/java/com/tokenview/api/config/APIConfiguration.java
new file mode 100644
index 0000000..094b12c
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/config/APIConfiguration.java
@@ -0,0 +1,126 @@
+package com.tokenview.api.config;
+
+import com.tokenview.api.constant.APIConstants;
+import com.tokenview.api.enums.I18nEnum;
+
+/**
+ * API configuration information
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2021/1/20 14:29
+ */
+public class APIConfiguration {
+
+ /**
+ * The user's api key provided by TokenView.
+ */
+ private String apiKey;
+ /**
+ * Rest api endpoint url.
+ */
+ private String endpoint;
+ /**
+ * Host connection timeout.
+ */
+ private long connectTimeout;
+ /**
+ * The host reads the information timeout.
+ */
+ private long readTimeout;
+ /**
+ * The host writes the information timeout.
+ */
+ private long writeTimeout;
+ /**
+ * Failure reconnection, default true.
+ */
+ private boolean retryOnConnectionFailure;
+ /**
+ * The print api information.
+ */
+ private boolean print;
+ /**
+ * I18nEnum
+ */
+ private I18nEnum i18n;
+
+ public APIConfiguration() {
+ this(null);
+ }
+ public APIConfiguration(String endpoint) {
+ super();
+ this.apiKey = null;
+ this.endpoint = endpoint;
+ this.connectTimeout = APIConstants.TIMEOUT;
+ this.readTimeout = APIConstants.TIMEOUT;
+ this.writeTimeout = APIConstants.TIMEOUT;
+ this.retryOnConnectionFailure = true;
+ this.print = false;
+ this.i18n = I18nEnum.ENGLISH;
+ }
+
+ public String getApiKey() {
+ return apiKey;
+ }
+
+ public void setApiKey(String apiKey) {
+ this.apiKey = apiKey;
+ }
+
+ public String getEndpoint() {
+ return endpoint;
+ }
+
+ public void setEndpoint(String endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ public long getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ public void setConnectTimeout(long connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ }
+
+ public long getReadTimeout() {
+ return readTimeout;
+ }
+
+ public void setReadTimeout(long readTimeout) {
+ this.readTimeout = readTimeout;
+ }
+
+ public long getWriteTimeout() {
+ return writeTimeout;
+ }
+
+ public void setWriteTimeout(long writeTimeout) {
+ this.writeTimeout = writeTimeout;
+ }
+
+ public boolean isRetryOnConnectionFailure() {
+ return retryOnConnectionFailure;
+ }
+
+ public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
+ this.retryOnConnectionFailure = retryOnConnectionFailure;
+ }
+
+ public boolean isPrint() {
+ return print;
+ }
+
+ public void setPrint(boolean print) {
+ this.print = print;
+ }
+
+ public I18nEnum getI18n() {
+ return i18n;
+ }
+
+ public void setI18n(I18nEnum i18n) {
+ this.i18n = i18n;
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/constant/APIConstants.java b/api-java-sdk/src/main/java/com/tokenview/api/constant/APIConstants.java
new file mode 100644
index 0000000..fbf904f
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/constant/APIConstants.java
@@ -0,0 +1,83 @@
+package com.tokenview.api.constant;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.api.enums.ContentTypeEnum;
+import okhttp3.MediaType;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.List;
+
+public class APIConstants {
+ /**
+ * The default timeout is 30 seconds.
+ */
+ public static final long TIMEOUT = 1000 * 30;
+ /**
+ * All requests and responses are application/json content type and follow typical HTTP response status codes for success and failure.
+ */
+ public static final String CONTENT_TYPE = "Content-Type";
+
+ public static final String ACCEPT = "Accept";
+
+ public static final String COOKIE = "Cookie";
+
+ public static final String LOCALE = "locale=";
+
+ public static final MediaType JSON = MediaType.parse(ContentTypeEnum.APPLICATION_JSON.contentType());
+
+ public static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ public static final String QUESTION = "?";
+
+ public static final String EMPTY = "";
+
+ public static final JSONObject NOTHING = new JSONObject();
+
+ public static final List toStringTypeArray = Arrays.asList(
+ "class java.lang.Long",
+ "class java.lang.Integer",
+ "long",
+ "int");
+ public static final List toStringTypeDoubleArray = Arrays.asList(
+ "class java.lang.Double",
+ "double");
+
+ public static final List resultStatusArray = Arrays.asList(
+ 400,401,429,500);
+
+ public static final String BOOLEAN = "boolean";
+ public static final String IS = "is";
+ public static final String get = "get";
+ public static final char a = 'a';
+ public static final char z = 'z';
+ public static final String ZERO_STRING = "0";
+ public static final String DOUBLE_ZERO_STRING = "0.00";
+
+ public static final String DOT1 = ".";
+ public static final String DOT2 = "\\.";
+ public static final String E = "E";
+ public static final String e = "e";
+ public static final int DEFAULT_SCALE = 2;
+ /**
+ * 8900000000.000000000
+ */
+ public static final String DOUBLE_END1 = "0+?$";
+ /**
+ * 8900000000.
+ */
+ public static final String DOUBLE_END2 = "[.]$";
+
+ /**
+ * default cursor id
+ */
+ public static final int ONE = 1;
+ /**
+ * max limit: 100
+ */
+ public static final int HUNDRED = 100;
+
+ public static final String HLINE = "-";
+
+ public static final String SLASH = "/";
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/enums/CharsetEnum.java b/api-java-sdk/src/main/java/com/tokenview/api/enums/CharsetEnum.java
new file mode 100644
index 0000000..8aae77c
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/enums/CharsetEnum.java
@@ -0,0 +1,24 @@
+package com.tokenview.api.enums;
+
+/**
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2020/1/18 13:00
+ */
+public enum CharsetEnum {
+
+ UTF_8("UTF-8"),
+ ISO_8859_1("ISO-8859-1"),;
+
+
+ private String charset;
+
+ CharsetEnum(String charset) {
+ this.charset = charset;
+ }
+
+ public String charset() {
+ return charset;
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/enums/ContentTypeEnum.java b/api-java-sdk/src/main/java/com/tokenview/api/enums/ContentTypeEnum.java
new file mode 100644
index 0000000..bfb3422
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/enums/ContentTypeEnum.java
@@ -0,0 +1,26 @@
+package com.tokenview.api.enums;
+
+/**
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2020/1/18 13:00
+ */
+public enum ContentTypeEnum {
+
+ APPLICATION_JSON("application/json"),
+ APPLICATION_JSON_UTF8("application/json; charset=UTF-8"),
+ // The server does not support types
+ APPLICATION_FORM("application/x-www-form-urlencoded; charset=UTF-8"),;
+
+
+ private String contentType;
+
+ ContentTypeEnum(String contentType) {
+ this.contentType = contentType;
+ }
+
+ public String contentType() {
+ return contentType;
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/enums/I18nEnum.java b/api-java-sdk/src/main/java/com/tokenview/api/enums/I18nEnum.java
new file mode 100644
index 0000000..f302eca
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/enums/I18nEnum.java
@@ -0,0 +1,24 @@
+package com.tokenview.api.enums;
+
+/**
+ * I18nEnum
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2020/1/18 13:00
+ */
+public enum I18nEnum {
+ ENGLISH("en_US"),
+ SIMPLIFIED_CHINESE("zh_CN"),
+ TRADITIONAL_CHINESE("zh_HK"),;
+
+ private String i18n;
+
+ I18nEnum(String i18n) {
+ this.i18n = i18n;
+ }
+
+ public String i18n() {
+ return i18n;
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/enums/ResultCode.java b/api-java-sdk/src/main/java/com/tokenview/api/enums/ResultCode.java
new file mode 100644
index 0000000..710bb13
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/enums/ResultCode.java
@@ -0,0 +1,111 @@
+package com.tokenview.api.enums;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * I18nEnum
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2020/1/18 13:00
+ */
+public enum ResultCode {
+
+ /* 成功状态码 */
+ SUCCESS(1, "成功"),
+ NO_DATA(404, "无数据"),
+
+ /* 参数错误:10001-19999 */
+ PARAM_IS_INVALID(10001, "参数无效"),
+ PARAM_IS_BLANK(10002, "参数为空"),
+ PARAM_TYPE_BIND_ERROR(10003, "参数类型错误"),
+ PARAM_NOT_COMPLETE(10004, "参数缺失"),
+
+ /* 用户中心错误:20001-29999*/
+ USER_NOT_LOGGED_IN(20001, "用户未登录"),
+ USER_LOGIN_ERROR(20002, "账号不存在或密码错误"),
+ USER_ACCOUNT_FORBIDDEN(20003, "账号已被禁用"),
+ USER_NOT_EXIST(20004, "用户不存在"),
+ USER_HAS_EXISTED(20005, "用户已存在"),
+ USER_COLLECTION_EXISTED(20006, "用户收藏已存在"),
+ USER_COLLECTION_SAVE_ERROR(20007, "用户收藏更新失败"),
+ USER_COLLECTION_DEL_ERROR(20008, "用户收藏删除失败"),
+ USER_COLLECTION_LOOK_ERROR(20008, "用户收藏查询失败"),
+
+ /* 业务错误:30001-39999 */
+ //SPECIFIED_QUESTIONED_USER_NOT_EXIST(30001, "某业务出现问题"),
+
+ /* 系统错误:40001-49999 */
+ SYSTEM_INNER_ERROR(40001, "系统繁忙,请稍后重试"),
+
+ /* 数据错误:50001-599999 */
+ RESULE_DATA_NONE(50001, "数据未找到"),
+ DATA_IS_WRONG(50002, "数据有误"),
+ DATA_ALREADY_EXISTED(50003, "数据已存在"),
+
+ /* 接口错误:60001-69999 */
+ INTERFACE_INNER_INVOKE_ERROR(60001, "内部系统接口调用异常"),
+ INTERFACE_OUTTER_INVOKE_ERROR(60002, "外部系统接口调用异常"),
+ INTERFACE_FORBID_VISIT(60003, "该接口禁止访问"),
+ INTERFACE_ADDRESS_INVALID(60004, "接口地址无效"),
+ INTERFACE_REQUEST_TIMEOUT(60005, "接口请求超时"),
+ INTERFACE_EXCEED_LOAD(60006, "接口负载过高"),
+
+ /* 权限错误:70001-79999 */
+ PERMISSION_NO_ACCESS(70001, "无访问权限");
+
+
+ private Integer code;
+
+ private String message;
+
+ ResultCode(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ public Integer code() {
+ return this.code;
+ }
+
+ public String message() {
+ return this.message;
+ }
+
+ public static String getMessage(String name) {
+ for (ResultCode item : ResultCode.values()) {
+ if (item.name().equals(name)) {
+ return item.message;
+ }
+ }
+ return name;
+ }
+
+ public static Integer getCode(String name) {
+ for (ResultCode item : ResultCode.values()) {
+ if (item.name().equals(name)) {
+ return item.code;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return this.name();
+ }
+
+ //校验重复的code值
+ public static void main(String[] args) {
+ ResultCode[] ApiResultCodes = ResultCode.values();
+ List codeList = new ArrayList();
+ for (ResultCode ApiResultCode : ApiResultCodes) {
+ if (codeList.contains(ApiResultCode.code)) {
+ System.out.println(ApiResultCode.code);
+ } else {
+ codeList.add(ApiResultCode.code());
+ }
+ }
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/exception/APIException.java b/api-java-sdk/src/main/java/com/tokenview/api/exception/APIException.java
new file mode 100644
index 0000000..6a08cfc
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/exception/APIException.java
@@ -0,0 +1,31 @@
+package com.tokenview.api.exception;
+
+public class APIException extends RuntimeException {
+ private int code;
+
+ public APIException(String message) {
+ super(message);
+ }
+
+ public APIException(int code, String message) {
+ super(message);
+ this.code = code;
+ }
+
+
+ public APIException(Throwable cause) {
+ super(cause);
+ }
+
+ public APIException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ @Override
+ public String getMessage() {
+ if (this.code != 0) {
+ return this.code + " : " + super.getMessage();
+ }
+ return super.getMessage();
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/result/HttpResult.java b/api-java-sdk/src/main/java/com/tokenview/api/result/HttpResult.java
new file mode 100644
index 0000000..9b0eb5f
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/result/HttpResult.java
@@ -0,0 +1,70 @@
+package com.tokenview.api.result;
+
+public class HttpResult {
+ private int code;
+ private String message;
+ private int errorCode;
+ private String errorMessage;
+ private String order_id;
+ private Boolean result;
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ public void setErrorCode(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getOrder_id() {
+ return order_id;
+ }
+
+ public void setOrder_id(String order_id) {
+ this.order_id = order_id;
+ }
+
+ public Boolean getResult() {
+ return result;
+ }
+
+ public void setResult(Boolean result) {
+ this.result = result;
+ }
+
+ @Override
+ public String toString() {
+ return "\t\tResponse Body:{" +
+ "code=" + code +
+ ", message='" + message + '\'' +
+ ", errorCode=" + errorCode +
+ ", errorMessage='" + errorMessage + '\'' +
+ ", order_id='" + order_id + '\'' +
+ ", result=" + result +
+ '}';
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/service/base/BaseService.java b/api-java-sdk/src/main/java/com/tokenview/api/service/base/BaseService.java
new file mode 100644
index 0000000..020d0e7
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/service/base/BaseService.java
@@ -0,0 +1,25 @@
+package com.tokenview.api.service.base;
+
+import com.alibaba.fastjson.JSONObject;
+
+public interface BaseService {
+
+ //获取指定交易详情
+ JSONObject getTransaction(String currency, String txid);
+
+ //获取UTXO(类BTC)指定地址交易列表
+ JSONObject getUTXOTransactionList(String currency, String address, String page, String size);
+
+ //获取ACCOUNT(类ETH/TRX)指定地址交易列表
+ JSONObject getACCOUNTTransactionList(String currency, String address, String page, String size);
+
+ //获取UTXO(类BTC)指定地址余额
+ JSONObject getUTXOAddressBalance(String currency, String address);
+
+ //获取ACCOUNT(类ETH/TRX)指定地址余额
+ JSONObject getACCOUNTAddressBalance(String currency, String address);
+
+ //T获取ACCOUNT(ETH,ETC,NAS,NEO)指定地址信息
+ JSONObject getACCOUNTAddressInfo(String currency, String address);
+
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseAPI.java b/api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseAPI.java
new file mode 100644
index 0000000..96a4689
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseAPI.java
@@ -0,0 +1,29 @@
+package com.tokenview.api.service.base.Impl;
+
+import com.alibaba.fastjson.JSONObject;
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Path;
+
+public interface BaseAPI {
+
+ @GET("/tx/{currency}/{txid}")
+ Call getTransaction(@Path("currency") String currency, @Path("txid") String txid);
+
+ @GET("/address/{currency}/{address}/{page}/{size}")
+ Call getTransactionList(@Path("currency") String currency, @Path("address") String address,
+ @Path("page") String page, @Path("size") String size);
+
+ @GET("/{currency}/address/normal/{address}/{page}/{size}")
+ Call getACCOUNTTransactionList(@Path("currency") String currency, @Path("address") String address,
+ @Path("page") String page, @Path("size") String size);
+
+ @GET("/address/{currency}/{address}/1/1")
+ Call getAddressBalance(@Path("currency") String currency, @Path("address") String address);
+
+ @GET("/addr/b/{currency}/{address}")
+ Call getACCOUNTAddressBalance(@Path("currency") String currency, @Path("address") String address);
+
+ @GET("/{currency}/address/{address}")
+ Call getACCOUNTAddressInfo(@Path("currency") String currency, @Path("address") String address);
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseServiceImpl.java b/api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseServiceImpl.java
new file mode 100644
index 0000000..bf9d940
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseServiceImpl.java
@@ -0,0 +1,47 @@
+package com.tokenview.api.service.base.Impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.api.client.APIClient;
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.service.base.BaseService;
+
+public class BaseServiceImpl implements BaseService {
+
+ private APIClient client;
+ private BaseAPI api;
+
+ public BaseServiceImpl(APIConfiguration config) {
+ this.client = new APIClient(config);
+ this.api = client.createService(BaseAPI.class);
+ }
+
+ @Override
+ public JSONObject getTransaction(String currency, String txid){
+ return this.client.executeSync(this.api.getTransaction(currency,txid));
+ }
+
+ @Override
+ public JSONObject getUTXOTransactionList(String currency,String address,String page,String size){
+ return this.client.executeSync(this.api.getTransactionList(currency,address,page,size));
+ }
+
+ @Override
+ public JSONObject getACCOUNTTransactionList(String currency,String address,String page,String size){
+ return this.client.executeSync(this.api.getACCOUNTTransactionList(currency,address,page,size));
+ }
+
+ @Override
+ public JSONObject getUTXOAddressBalance(String currency,String address){
+ return this.client.executeSync(this.api.getAddressBalance(currency,address));
+ }
+
+ @Override
+ public JSONObject getACCOUNTAddressBalance(String currency,String address){
+ return this.client.executeSync(this.api.getACCOUNTAddressBalance(currency,address));
+ }
+
+ @Override
+ public JSONObject getACCOUNTAddressInfo(String currency,String address){
+ return this.client.executeSync(this.api.getACCOUNTAddressInfo(currency,address));
+ }
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/WalletService.java b/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/WalletService.java
new file mode 100644
index 0000000..570bef4
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/WalletService.java
@@ -0,0 +1,16 @@
+package com.tokenview.api.service.wallet;
+
+import com.alibaba.fastjson.JSONObject;
+
+public interface WalletService {
+
+ //发送ETH/BTC交易到对应区块链
+ JSONObject sendRawTransaction(String currency, JSONObject jo);
+
+ //获取ACCOUNT(类ETH/TRX)指定地址信息
+ JSONObject getACCOUNTAddressNonce(String currency, JSONObject jo);
+
+ //获取TRX签名前内容
+ JSONObject getTRXCreateTransaction(JSONObject jo);
+
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletAPI.java b/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletAPI.java
new file mode 100644
index 0000000..74440df
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletAPI.java
@@ -0,0 +1,20 @@
+package com.tokenview.api.service.wallet.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import retrofit2.Call;
+import retrofit2.http.Body;
+import retrofit2.http.POST;
+import retrofit2.http.Path;
+
+public interface WalletAPI {
+
+ @POST("/onchainwallet/{currency}")
+ Call sendRawTransaction(@Path("currency") String currency, @Body JSONObject jsonObject);
+
+ @POST("/onchainwallet/{currency}")
+ Call getACCOUNTAddressNonce(@Path("currency") String currency, @Body JSONObject jsonObject);
+
+ @POST("/onchainwallet/trx")
+ Call getTRXCreateTransaction(@Body JSONObject jsonObject);
+
+}
diff --git a/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletServiceImpl.java b/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletServiceImpl.java
new file mode 100644
index 0000000..3572770
--- /dev/null
+++ b/api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletServiceImpl.java
@@ -0,0 +1,36 @@
+package com.tokenview.api.service.wallet.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.api.client.APIClient;
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.service.wallet.WalletService;
+
+public class WalletServiceImpl implements WalletService {
+
+ private APIClient client;
+ private WalletAPI api;
+
+ public WalletServiceImpl(APIConfiguration config) {
+ this.client = new APIClient(config);
+ this.api = client.createService(WalletAPI.class);
+ }
+
+ @Override
+ public JSONObject sendRawTransaction(String currency,JSONObject jsonObject){
+ return this.client.executeSync(this.api.sendRawTransaction(currency,jsonObject));
+ }
+
+ @Override
+ public JSONObject getACCOUNTAddressNonce(String currency,JSONObject jsonObject){
+ return this.client.executeSync(this.api.getACCOUNTAddressNonce(currency,jsonObject));
+ }
+
+ @Override
+ public JSONObject getTRXCreateTransaction(JSONObject jsonObject){
+ return this.client.executeSync(this.api.getTRXCreateTransaction(jsonObject));
+ }
+
+
+
+
+}
diff --git a/api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseAPITest.java b/api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseAPITest.java
new file mode 100644
index 0000000..128579d
--- /dev/null
+++ b/api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseAPITest.java
@@ -0,0 +1,99 @@
+package com.tokenview.api.test.base;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.api.service.base.BaseService;
+import com.tokenview.api.service.base.Impl.BaseServiceImpl;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * TokenView API Test
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2021/1/20 11:13
+ */
+public class BaseAPITest extends BaseConfig{
+
+ private BaseService baseService;
+
+ @Before
+ public void before() {
+ config = config();
+ baseService = new BaseServiceImpl(config);
+ }
+
+ /**
+ * 查看交易详情,支持类BTC,类ETH,TRX等tokenview支持的所有币的交易查询
+ * GET /tx/{currency}/{txid}
+ */
+ @Test
+ public void testGetTransaction(){
+ JSONObject result = baseService.getTransaction("btc","6680c65d3b1f4ab61b7096441a257de51f8bab48d0dca2f76080891ad9b0796a");
+ toResultString("GetTransaction", result);
+ }
+
+ /**
+ * 查看UTXO(类BTC)指定地址余额
+ * GET /address/{currency}/{address}/{page}/{size}
+ */
+ @Test
+ public void testGetUTXOAddressBalance(){
+ JSONObject result = baseService.getUTXOAddressBalance("btc","1AqSbAsXh3zxE8Z61afpU65u4pxB9BBRcz");
+ toResultString("GetUTXOAddressBalance", result);
+ }
+
+ /**
+ * 查看UTXO(类BTC)指定地址交易列表
+ * GET /address/{currency}/{address}/{page}/{size}
+ */
+ @Test
+ public void testGetUTXOTransactionList(){
+ JSONObject result = baseService.getUTXOTransactionList("btc","1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ","1","50");
+ toResultString("GetUTXOTransactionList", result);
+ }
+
+ /**
+ * 查看ACCOUNT(类ETH/TRX)指定地址余额
+ * GET /address/{currency}/{address}/{page}/{size}
+ */
+ @Test
+ public void testGetACCOUNTAddressBalance(){
+ JSONObject result = baseService.getACCOUNTAddressBalance("eth","0xda9cacf6c13450bea275c33e83503fb705d27bbb");
+ toResultString("GetACCOUNTAddressBalance", result);
+ }
+
+ /**
+ * 查看获取ACCOUNT(类ETH/TRX)指定地址交易列表
+ * GET /{currency}/address/normal/{address}/{page}/{size}
+ */
+ @Test
+ public void testGetACCOUNTTransactionList(){
+ JSONObject result = baseService.getACCOUNTTransactionList("eth","0x58b6a8a3302369daec383334672404ee733ab239","1","50");
+ toResultString("GetACCOUNTTransactionList", result);
+ }
+
+ /**
+ * 查看ACCOUNT(ETH,ETC,NAS,NEO)指定地址详细信息
+ * GET /{currency}/address/{address}
+ */
+ @Test
+ public void getACCOUNTAddressInfo(){
+ JSONObject result = baseService.getACCOUNTAddressInfo("eth","0xda9cacf6c13450bea275c33e83503fb705d27bbb");
+ toResultString("GetACCOUNTAddressInfo", result);
+ }
+
+ /**
+ * 获取账户类型(类eth)地址信息(nonce),目前支持ETH,ETC,NAS,NEO,其他币暂时不支持
+ *
+ */
+ @Test
+ public void getACCOUNTAddressNonce(){
+ String nonce = baseService.getACCOUNTAddressInfo("eth","0xda9cacf6c13450bea275c33e83503fb705d27bbb")
+ .getJSONObject("data")
+ .getString("nonce");
+ toResultString("GetACCOUNTAddressNonce", nonce);
+ }
+
+
+}
diff --git a/api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseConfig.java b/api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseConfig.java
new file mode 100644
index 0000000..94b6529
--- /dev/null
+++ b/api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseConfig.java
@@ -0,0 +1,29 @@
+package com.tokenview.api.test.base;
+
+import com.alibaba.fastjson.JSON;
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.enums.I18nEnum;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class BaseConfig {
+ public APIConfiguration config;
+
+ public APIConfiguration config() {
+ APIConfiguration config = new APIConfiguration();
+
+ config.setEndpoint("http://www.tokenview.com:8088/");
+ config.setApiKey("ab2ac254-b5b3-4b13-bdea-e5d9a12319d7");
+
+ config.setPrint(true);
+ config.setI18n(I18nEnum.ENGLISH);
+
+ return config;
+ }
+
+ public void toResultString(String flag, Object object) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(flag).append(":\n").append(JSON.toJSONString(object));
+ System.out.println(stringBuilder);
+ }
+}
diff --git a/api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesAPITest.java b/api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesAPITest.java
new file mode 100644
index 0000000..5157b2f
--- /dev/null
+++ b/api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesAPITest.java
@@ -0,0 +1,11 @@
+package com.tokenview.api.test.services;
+
+/**
+ * TokenView API Test
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2021/1/20 11:44
+ */
+public class ServicesAPITest extends ServicesConfig {
+}
diff --git a/api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesConfig.java b/api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesConfig.java
new file mode 100644
index 0000000..691cf8e
--- /dev/null
+++ b/api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesConfig.java
@@ -0,0 +1,30 @@
+package com.tokenview.api.test.services;
+
+import com.alibaba.fastjson.JSON;
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.enums.I18nEnum;
+
+public class ServicesConfig {
+
+
+ public APIConfiguration config;
+
+ public APIConfiguration config() {
+ APIConfiguration config = new APIConfiguration();
+ // apiKey,api注册成功后页面上有
+ //config.setEndpoint("https://wallet.tokenview.com/");
+ config.setEndpoint("http://www.tokenview.com:8088/");
+ config.setApiKey("ab2ac254-b5b3-4b13-bdea-e5d9a12319d7");
+
+ config.setPrint(true);
+ config.setI18n(I18nEnum.ENGLISH);
+
+ return config;
+ }
+
+ public void toResultString(String flag, Object object) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(flag).append(":\n").append(JSON.toJSONString(object));
+ System.out.println(stringBuilder);
+ }
+}
diff --git a/api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletAPITest.java b/api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletAPITest.java
new file mode 100644
index 0000000..006bf81
--- /dev/null
+++ b/api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletAPITest.java
@@ -0,0 +1,187 @@
+package com.tokenview.api.test.wallet;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.api.service.wallet.WalletService;
+import com.tokenview.api.service.wallet.impl.WalletServiceImpl;
+import com.tokenview.sign.btc.BTCSign;
+import com.tokenview.sign.eth.ETHSign;
+import com.tokenview.utils.BTCWalletUtil;
+import com.tokenview.utils.HttpUtil;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * TokenView API Test
+ *
+ * @author Moilk
+ * @version 1.0.0
+ * @date 2021/1/20 16:09
+ */
+public class WalletAPITest extends WalletConfig {
+
+ private WalletService walletservice;
+
+ @Before
+ public void before() {
+ config = config();
+ walletservice = new WalletServiceImpl(config);
+ }
+ /**由助记词得到eckey+wif格式私钥+hex格式私钥,适用于类BTC币和类ETH币,详细见打印信息,请注意以下两点
+ * 类BTC币请使用BTC_MAIN_PATH
+ * 类ETH币请使用ETH_MAIN_PATH
+ * 使用对的chainpath才能和目前市场主流钱包生成地址相同,否则不同!!!!
+ * @Param List
+ */
+ @Test
+ public void getEckey(){
+ List stringList = new ArrayList();
+ stringList.add("gym");
+ stringList.add("please");
+ stringList.add("sauce");
+ stringList.add("elephant");
+ stringList.add("trap");
+ stringList.add("bag");
+ stringList.add("logic");
+ stringList.add("okay");
+ stringList.add("impulse");
+ stringList.add("slogan");
+ stringList.add("goose");
+ stringList.add("birth");
+ BTCWalletUtil.loadWalletByMnemonic("btc",stringList,"bc1q44elpv05mkdkp5qyd8fajcq2lrczpsats7zjgr","mywallet");
+ BTCWalletUtil.loadWalletByMnemonic("eth",stringList,"bc1q44elpv05mkdkp5qyd8fajcq2lrczpsats7zjgr","mywallet");
+ }
+
+ /**
+ * 创建账户类型(类eth)地址
+ * @Param privateKey
+ */
+ @Test
+ public void createACCOUNTAddress(){
+ toResultString("CreateACCOUNTAddress", new ETHSign().getAddress("b71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f"));
+ }
+
+ /**
+ * 创建UTXO(类BTC)地址
+ * @Param privateKey
+ */
+ @Test
+ public void createUTXOAddress(){
+ toResultString("CreateUTXOAddress",new BTCSign().getAddress("ab4ff104eddcc43430e0afe9487f21e1033fdc4eca9448065593d49fbc5e6b53"));
+ }
+
+
+ /**
+ * 使用私钥对账户类型(类eth)地址发交易进行签名,nonce调用BaseAPI获取,gasPrice和gasLimit可使用下面固定值约 $2/笔
+ * @Param privateKey
+ * @Param toAddress
+ * @Param nonce
+ * @Param gasPrice
+ * @Param gasLimit
+ * @Param amount
+ */
+ @Test
+ public void SignEthTransaction(){
+ toResultString("SignEthTransaction", new ETHSign().signETHTransaction(
+ "0xb71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f",
+ "0x9Ae75431335d2e70f8DB0b35F6C179a43756f78e",
+ "1",
+ 78500000000L,
+ 21000L,
+ 100000000L));
+ }
+
+ /**
+ * 使用私钥对UTXO类型(类BTC)地址发交易进行签名,包含获取unspent并组装交易过程,暂不支持隔离见证bech32地址
+ * @Param txid
+ * @Param inputAddress(可若干个)
+ * @Param toAddress(可若干个)
+ * @Param toAmount(可若干个)
+ * @Param changeAddress
+ * @Param privateKeyWif(privateKeyHex也可只要能生成Eckey,本次测试用wif格式)
+ */
+ @Test
+ public void SignBTCTransaction(){
+ //unspent所在txid和所在地址
+ String txid = "6680c65d3b1f4ab61b7096441a257de51f8bab48d0dca2f76080891ad9b0796a";
+ String inputAddress="1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ";
+ String toAdddress = "3Kjn9rsoQPrHQXGCJjJuuqZe46JNAseN1t";
+ long toAmount = 10000;
+ String changeAddress="1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ";
+ String privateKeyWIF = "L2xigpefbyesCnzR5hJDFxKPD4A2qSuNHiz4utWnqEovhownw8U2";
+
+ List addrList = new ArrayList<>();
+ addrList.add(inputAddress);
+ //可自行设置多个输出地址和金额,找零地址和金额
+ JSONArray unspents =new HttpUtil().getUnspent(txid,addrList);
+ long inputAmount =unspents
+ .stream()
+ .mapToLong(o->JSONObject.parseObject(o.toString()).getLong("value"))
+ .sum();
+
+ JSONArray outputs = new JSONArray();
+ JSONObject outputTo = new JSONObject();
+ outputTo.put("address",toAdddress);
+ outputTo.put("amount",toAmount);
+ outputs.add(outputTo);
+ long outputToAmount = outputs
+ .stream()
+ .mapToLong(o -> JSONObject.parseObject(o.toString()).getLong("amount"))
+ .sum();
+ long outputChangeAmount = inputAmount - outputToAmount;
+ //input金额不足输出和找零返回不签名
+ if (outputChangeAmount<=0){
+ return;
+ }
+ JSONObject outputChange = new JSONObject();
+ outputChange.put("address",changeAddress);
+ outputChange.put("amount",outputChangeAmount);
+
+ outputs.add(outputChange);
+
+ //找零金额小于等于手续费返回不签名
+ long fee = (unspents.size() + outputs.size() * 2) * 148 - 10;
+ if (outputChangeAmount <= fee) {
+ return;
+ }
+ toResultString("SignBTCTransaction",new BTCSign().signBTCTransaction(privateKeyWIF,unspents,outputs));
+ }
+
+
+ /**
+ * 广播类btc/eth/etc交易上链,对应不同method,注意替换
+ * POST /onchainwallet/{currency}
+ * @Param method
+ * @Param signature
+ * @Param currency
+ */
+ @Test
+ public void testSendETHRawTransaction() {
+
+ JSONObject jo =new JSONObject();
+ jo.put("jsonrpc","2.0");
+ jo.put("id","viewtoken");
+ jo.put("method","eth_sendRawTransaction");
+ jo.put("params", Arrays.asList("0xf86801851246f6f100825208949ae75431335d2e70f8db0b35f6c179a43756f78e8405f5e100801ca058b2130954d3b84918db5c0fc309dcc942b8656d88964a5f981a4a954bbb1221a0788b6b75afaea28d2e9178a6cea3d432983c10db1c778a1dcb6af009f5457701"));
+ JSONObject onchainwallet = walletservice.sendRawTransaction("eth",jo);
+ toResultString("SendRawTransaction", onchainwallet);
+ }
+ @Test
+ public void testSendBTCRawTransaction(){
+ JSONObject jo =new JSONObject();
+ jo.put("jsonrpc","2.0");
+ jo.put("id","viewtoken");
+ jo.put("method","sendrawtransaction");
+ jo.put("params", Arrays.asList("01000000016a79b0d91a898060f7a2dcd048ab8b1fe57d251a4496701bb64a1f3b5dc68066010000006b483045022100f5c22019fdd167dfe16988cabbe31a4eeda609abfd8369612813cd510cadca5102201270c8dca6a6b7826162d7f5b00c7a479ad32505a55e958301473bdcab72079f8121033efaa795ed22b1531127a3fd5b6e72031f6a7f4370fb67367768054ef011def0ffffffff02102700000000000017a914c64907144796b4177d6b5809c388c437385db4bb879ab00000000000001976a914d2ed73cd81bb2d516411c47a8ddb02ae5f2e7d0188ac00000000"));
+ JSONObject onchainwallet = walletservice.sendRawTransaction("btc",jo);
+ toResultString("SendRawTransaction", onchainwallet);
+ }
+
+
+
+
+}
diff --git a/api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletConfig.java b/api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletConfig.java
new file mode 100644
index 0000000..469ba8a
--- /dev/null
+++ b/api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletConfig.java
@@ -0,0 +1,29 @@
+package com.tokenview.api.test.wallet;
+
+import com.alibaba.fastjson.JSON;
+import com.tokenview.api.config.APIConfiguration;
+import com.tokenview.api.enums.I18nEnum;
+
+public class WalletConfig {
+
+ public APIConfiguration config;
+
+ public APIConfiguration config() {
+ APIConfiguration config = new APIConfiguration();
+ // apiKey,api注册成功后页面上有
+ config.setEndpoint("https://wallet.tokenview.com/");
+ config.setApiKey("ab2ac254-b5b3-4b13-bdea-e5d9a12319d7");
+
+ config.setPrint(true);
+ config.setI18n(I18nEnum.ENGLISH);
+
+ return config;
+ }
+
+ public void toResultString(String flag, Object object) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(flag).append(":\n").append(JSON.toJSONString(object));
+ System.out.println(stringBuilder);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..1704cf6
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+
+ com.tokenview
+ api-demo
+ pom
+ 1.0.0
+
+ sign-java-sdk
+ api-java-sdk
+
+
+
+
diff --git a/sign-java-sdk/pom.xml b/sign-java-sdk/pom.xml
new file mode 100644
index 0000000..a892428
--- /dev/null
+++ b/sign-java-sdk/pom.xml
@@ -0,0 +1,210 @@
+
+
+
+ api-demo
+ com.tokenview
+ 1.0.0
+
+ 4.0.0
+
+ com.tokenview
+ sign-java-sdk
+ 1.0.0
+
+
+
+ cash.bitcoinj
+ bitcoinj-tools
+ 0.14.5.2
+
+
+
+
+
+
+
+ org.web3j
+ core
+ 3.0.1
+
+
+ jnr-ffi
+ com.github.jnr
+
+
+ okio
+ com.squareup.okio
+
+
+ bcprov-jdk15on
+ org.bouncycastle
+
+
+ slf4j-api
+ org.slf4j
+
+
+ okhttp
+ com.squareup.okhttp3
+
+
+ jackson-databind
+ com.fasterxml.jackson.core
+
+
+
+
+ org.web3j
+ crypto
+ 4.2.0
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.8.0-beta2
+
+
+ org.springframework
+ spring-context
+ 5.1.5.RELEASE
+
+
+ com.squareup.retrofit2
+ converter-scalars
+ 2.3.0
+
+
+ com.squareup.retrofit2
+ converter-gson
+ 2.3.0
+
+
+ com.squareup.retrofit2
+ adapter-rxjava
+ 2.3.0
+
+
+ org.apache.commons
+ commons-lang3
+ 3.7
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+
+
+ com.google.guava
+ guava
+ 27.1-jre
+
+
+ commons-codec
+ commons-codec
+ 1.12
+
+
+ org.apache.commons
+ commons-compress
+ 1.18
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.5
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.9.3
+
+
+ commons-collections
+ commons-collections
+ 3.2.1
+
+
+ commons-logging
+ commons-logging
+ 1.1.1
+
+
+ net.sf.ezmorph
+ ezmorph
+ 1.0.6
+
+
+ com.alibaba
+ fastjson
+ 1.2.12
+
+
+ net.sf.json-lib
+ json-lib
+ 2.2.3
+ jdk15
+
+
+ org.springframework
+ spring-web
+ 5.0.9.RELEASE
+ test
+
+
+ jstl
+ jstl
+ 1.2
+ test
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ com.madgag.spongycastle
+ prov
+ 1.58.0.0
+
+
+
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.8
+
+
+ org.bitcoincashj
+ bitcoincashj-core
+ 1.1.0-SNAPSHOT
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.8
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sign-java-sdk/sign-java-sdk.iml b/sign-java-sdk/sign-java-sdk.iml
new file mode 100644
index 0000000..e5fc851
--- /dev/null
+++ b/sign-java-sdk/sign-java-sdk.iml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sign-java-sdk/src/main/java/com/tokenview/bean/WalletBean.java b/sign-java-sdk/src/main/java/com/tokenview/bean/WalletBean.java
new file mode 100644
index 0000000..50da4cc
--- /dev/null
+++ b/sign-java-sdk/src/main/java/com/tokenview/bean/WalletBean.java
@@ -0,0 +1,67 @@
+package com.tokenview.bean;
+
+public class WalletBean {
+ private String coin_type;
+ private String mnemonic;
+ private String address;
+ private String keystore;
+ private String privateKey;
+ private String name;
+ private int insert_type;
+
+ public String getCoin_type() {
+ return coin_type;
+ }
+
+ public void setCoin_type(String coin_type) {
+ this.coin_type = coin_type;
+ }
+
+ public String getMnemonic() {
+ return mnemonic;
+ }
+
+ public void setMnemonic(String mnemonic) {
+ this.mnemonic = mnemonic;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getKeystore() {
+ return keystore;
+ }
+
+ public void setKeystore(String keystore) {
+ this.keystore = keystore;
+ }
+
+ public String getPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(String privateKey) {
+ this.privateKey = privateKey;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getInsert_type() {
+ return insert_type;
+ }
+
+ public void setInsert_type(int insert_type) {
+ this.insert_type = insert_type;
+ }
+}
diff --git a/sign-java-sdk/src/main/java/com/tokenview/enums/Version.java b/sign-java-sdk/src/main/java/com/tokenview/enums/Version.java
new file mode 100644
index 0000000..81b1b72
--- /dev/null
+++ b/sign-java-sdk/src/main/java/com/tokenview/enums/Version.java
@@ -0,0 +1,15 @@
+package com.tokenview.enums;
+
+public enum Version {
+ BTC(1);
+
+ private Integer version;
+
+ Version(Integer version) {
+ this.version = version;
+ }
+
+ public Integer getVersion() {
+ return version;
+ }
+}
diff --git a/sign-java-sdk/src/main/java/com/tokenview/sign/btc/BTCSign.java b/sign-java-sdk/src/main/java/com/tokenview/sign/btc/BTCSign.java
new file mode 100644
index 0000000..7dd15f6
--- /dev/null
+++ b/sign-java-sdk/src/main/java/com/tokenview/sign/btc/BTCSign.java
@@ -0,0 +1,59 @@
+package com.tokenview.sign.btc;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.enums.Version;
+import org.bitcoinj.core.*;
+import org.bitcoinj.params.MainNetParams;
+import org.bitcoinj.script.Script;
+import org.spongycastle.util.encoders.Hex;
+
+public class BTCSign {
+ public String signBTCTransaction(String privateKey,JSONArray unspents,JSONArray outputs) {
+ String hexString = "";
+ try {
+ NetworkParameters params = MainNetParams.get();
+ DumpedPrivateKey priKey = DumpedPrivateKey.fromBase58(params,privateKey);
+ ECKey ecKey = priKey.getKey();
+ System.out.println(ecKey.getPrivateKeyAsHex());
+ System.out.println(ecKey.getPublicKeyAsHex());
+ System.out.println(new String(ecKey.getPubKeyHash()));
+ //构建交易体
+ Transaction transaction = new Transaction(params);
+ //交易的版本 默认的BTC,LTC ,DOGE,DASH 版本号是1, BCH BSV 版本号是:2;
+ transaction.setVersion(Version.BTC.getVersion());
+ long fee = (unspents.size() + outputs.size() * 2) * 148 - 10;
+ //添加转出到的地址列表和数量
+ for(int i = 0;i inputParameters = new ArrayList<>();
+ inputParameters.add(new Address(toAddress));
+ inputParameters.add(new Uint256(0L));//转出数量
+ List> outputParameters = new ArrayList<>();
+ //调用的合约的方法 transfer,参数,输出 等等
+ Function function = new Function("transfer", inputParameters, outputParameters);
+ //将合约数据转换成16进制字符串
+ String dataStr = FunctionEncoder.encode(function);
+ RawTransaction tx = RawTransaction.createTransaction(
+ BigInteger.valueOf(Long.parseLong(nonce)),
+ BigInteger.valueOf(gasPrice),//gasPrice
+ BigInteger.valueOf(gasLimit),//gasLimit
+ toAddress,
+ BigInteger.valueOf(amount),//转账的"数量"
+ "");
+ //创建钥匙对
+ ECKeyPair ecKeyPair = ECKeyPair.create(Numeric.toBigInt(privateKey));
+ Credentials credentials = Credentials.create(ecKeyPair);
+ System.out.println(credentials.getAddress());
+ //签名交易
+ byte[] signed = TransactionEncoder.signMessage(tx, credentials);
+ //将签名的交易转换成16进制字符串,并用于广播交易
+ signedStr = Numeric.toHexString(signed);
+ } catch (Exception e) {
+
+ }
+ return signedStr;
+ }
+
+ public String getAddress(String privateKey){
+ ECKeyPair ecKeyPair = ECKeyPair.create(Numeric.toBigInt(privateKey));
+ Credentials credentials = Credentials.create(ecKeyPair);
+ return credentials.getAddress();
+ }
+}
diff --git a/sign-java-sdk/src/main/java/com/tokenview/utils/BTCWalletUtil.java b/sign-java-sdk/src/main/java/com/tokenview/utils/BTCWalletUtil.java
new file mode 100644
index 0000000..4f4bade
--- /dev/null
+++ b/sign-java-sdk/src/main/java/com/tokenview/utils/BTCWalletUtil.java
@@ -0,0 +1,304 @@
+package com.tokenview.utils;
+
+
+import com.tokenview.bean.WalletBean;
+import org.apache.commons.lang3.StringUtils;
+import org.bitcoinj.core.*;
+import org.bitcoinj.crypto.ChildNumber;
+import org.bitcoinj.crypto.DeterministicKey;
+import org.bitcoinj.crypto.HDKeyDerivation;
+import org.bitcoinj.params.MainNetParams;
+import org.bitcoinj.wallet.DeterministicSeed;
+import org.bouncycastle.util.encoders.Hex;
+import org.web3j.crypto.ECKeyPair;
+import org.web3j.utils.Numeric;
+
+import java.util.List;
+
+
+public class BTCWalletUtil {
+
+ // public static boolean BTC_TEST_NET = SharedPreferencesUtil.getInstance().getBoolean(NumberConstant.IS_TEST_NET,false);
+ public static String BTC_TEST_PATH = "m/44'/1'/0'/0/0";
+ public static String BTC_MAIN_PATH = "m/44'/0'/0'/0/0";
+ public static String BTC_SEGWIT_MAIN_PATH = "m/49'/0'/0'/0/0";
+ public static String BTC_SEGWIT_TEST_PATH = "m/49'/1'/0'/0/0";
+ public static String ETH_MAIN_PATH="m/44'/60'/0'/0/0";
+
+ /**
+ * 通过助记词生成私钥
+ */
+ public static WalletBean loadWalletByDeterministicSeed(DeterministicSeed ds, String pwd, String walletName) {
+ String path;
+ NetworkParameters params;
+ path = BTC_MAIN_PATH;
+ params = MainNetParams.get();
+ ECKeyPair keyPair = getEcKeyPairByDeterministicSeed(path, ds);
+// loadWalletBIP49ByDeterministicSeed(ds);
+ if (keyPair == null) return null;
+ // 获取Base64编码的64位的私钥
+// String privateKey = Numeric.toHexStringNoPrefixZeroPadded(keyPair.getPrivateKey(), Keys.PRIVATE_KEY_LENGTH_IN_HEX);
+// //第二种方式生成
+// ECKeyPair ecKeyPair = generateEcKeyPair(ds);
+ ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey());
+ //获取Base58编码压缩后的私钥
+ String privateKeyAsWiF = ecKey.getPrivateKeyAsWiF(params);
+ String address = ecKey.toAddress(params).toString();
+ WalletBean bean = new WalletBean();
+ bean.setCoin_type("BTC");
+ bean.setMnemonic(getMnemonic(ds));
+ bean.setAddress(address);
+ bean.setKeystore("");
+ bean.setPrivateKey(privateKeyAsWiF);
+ bean.setName(walletName);
+ return bean;
+ }
+
+
+ /**
+ * 通过助记词生成 BIP49 协议的隔离见证地址
+ */
+ public static WalletBean loadWalletBIP49ByDeterministicSeed(List mnemonic) {
+ DeterministicSeed ds = getDeterministicSeed(mnemonic);
+ String path=BTC_SEGWIT_MAIN_PATH;
+ NetworkParameters params= MainNetParams.get();
+ String[] pathArray = path.split("/");
+ byte[] seedBytes = ds.getSeedBytes();
+ DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes);
+ for (int i = 1; i < pathArray.length; i++) {
+ ChildNumber childNumber;
+ if (pathArray[i].endsWith("'")) {
+ int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1));
+ childNumber = new ChildNumber(number, true);
+ } else {
+ int number = Integer.parseInt(pathArray[i]);
+ childNumber = new ChildNumber(number, false);
+ }
+ dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber);
+ }
+ //获取P2SH地址的过程
+ String publicKey=Numeric.toHexStringNoPrefix(dkKey.getPubKeyHash());
+ String redeemScript = String.format("0x0014%s", publicKey);
+ byte[] bytes = Numeric.hexStringToByteArray(redeemScript);
+ byte[] bytes1 = Utils.sha256hash160(bytes);
+ String p2shAddress = Address.fromP2SHHash(params, bytes1).toBase58();
+ System.out.println("p2sh address == "+p2shAddress);
+ WalletBean bean=new WalletBean();
+ bean.setCoin_type("BTC");
+ bean.setName("BTC");
+ bean.setAddress(p2shAddress);
+ bean.setMnemonic(getMnemonic(ds));
+ bean.setInsert_type(1);
+ bean.setPrivateKey(dkKey.getPrivateKeyAsWiF(params));
+ return bean;
+ }
+
+
+
+ /**
+ * 通过助记词生成hex私钥,WIF私钥,也可生成地址
+ */
+ public static WalletBean loadWalletByDeterministicSeedTest(DeterministicSeed ds, String pwd, String walletName) {
+ String path;
+ NetworkParameters params;
+ path = BTC_MAIN_PATH;
+ params = MainNetParams.get();
+ //params = TestNet3Params.get();
+ ECKeyPair keyPair = getEcKeyPairByDeterministicSeed(path, ds);
+ if (keyPair == null) return null;
+ // 获取Base64编码的64位的私钥
+// String privateKey = Numeric.toHexStringNoPrefixZeroPadded(keyPair.getPrivateKey(), Keys.PRIVATE_KEY_LENGTH_IN_HEX);
+ // 第二种方式生成
+ // ECKeyPair ecKeyPair = generateEcKeyPair(ds);
+ ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey());
+ String hexPrivateKey = ecKey.getPrivateKeyAsHex();
+ ECKey ecKey1 = ECKey.fromPrivate(Hex.decode(hexPrivateKey));
+ Address address1 = ecKey1.toAddress(params);
+ System.out.println("bitcoin address == "+address1);
+ //获取Base58编码压缩后的私钥
+ System.out.println("privateKeyHex == "+ecKey.getPrivateKeyAsHex());
+ //ecKey.
+ String privateKeyAsWiF = ecKey.getPrivateKeyAsWiF(params);
+ System.out.println("privateKeyWif =="+privateKeyAsWiF);
+ String address = ecKey.toAddress(params).toString();
+ System.out.println("bitcoin address == "+address);
+ WalletBean bean = new WalletBean();
+ bean.setCoin_type("BTC");
+ bean.setMnemonic(getMnemonic(ds));
+ bean.setAddress(address);
+ bean.setKeystore("");
+ bean.setPrivateKey(privateKeyAsWiF);
+ bean.setName(walletName);
+ return bean;
+ }
+
+ /**
+ * 通过私钥导入BTC钱包 (base58)
+ * */
+ public static WalletBean loadWalletByPrivateKey(String privateKey) {
+ NetworkParameters params;
+ params = MainNetParams.get();
+ try {
+ DumpedPrivateKey priKey = DumpedPrivateKey.fromBase58(params, privateKey);
+ ECKey ecKey = priKey.getKey();
+ String address = ecKey.toAddress(params).toString();
+ WalletBean bean = new WalletBean();
+ bean.setCoin_type("BTC");
+ bean.setMnemonic(" ");
+ bean.setAddress(address);
+ bean.setKeystore("");
+ bean.setPrivateKey(privateKey);
+ bean.setName(" ");
+ return bean;
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * 通过助记词生成私钥
+ */
+ public static WalletBean loadWalletByMnemonic(String currency,List list, String pwd, String walletName) {
+ String path;
+ NetworkParameters params;
+ path = "";
+ if (currency.equalsIgnoreCase("btc")) {
+ path = BTC_MAIN_PATH;
+ }
+ if (currency.equalsIgnoreCase("eth")) {
+ path = ETH_MAIN_PATH;
+ }
+ params = MainNetParams.get();
+ DeterministicSeed ds = getDeterministicSeed(list);
+ ECKeyPair keyPair = getEcKeyPairByDeterministicSeed(path, ds);
+// //获取16编码的64位的私钥
+// String privateKey = Numeric.toHexStringNoPrefixZeroPadded(keyPair.getPrivateKey(), Keys.PRIVATE_KEY_LENGTH_IN_HEX);
+// ECKeyPair ecKeyPair = generateEcKeyPair(ds);
+ ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey());
+ //获取Base58编码压缩后的私钥
+ String privateKeyAsWiF = ecKey.getPrivateKeyAsWiF(params);
+ String address = ecKey.toAddress(params).toString();
+ System.out.println("privateKey ===="+ecKey.getPrivateKeyAsHex());
+ System.out.println("address ====="+address);
+ WalletBean bean = new WalletBean();
+ bean.setCoin_type("BTC");
+ bean.setMnemonic(getMnemonic(ds));
+ bean.setAddress(address);
+ bean.setKeystore("");
+ bean.setPrivateKey(privateKeyAsWiF);
+ bean.setName(walletName);
+ return bean;
+ }
+
+
+ /**
+ * 通过路径和种子获取私钥对
+ */
+ public static ECKeyPair getEcKeyPairByDeterministicSeed(String path, DeterministicSeed ds) {
+ String[] pathArray = path.split("/");
+ byte[] seedBytes = ds.getSeedBytes();
+ if (seedBytes == null)
+ return null;
+ DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes);
+ for (int i = 1; i < pathArray.length; i++) {
+ ChildNumber childNumber;
+ if (pathArray[i].endsWith("'")) {
+ int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1));
+ childNumber = new ChildNumber(number, true);
+ } else {
+ int number = Integer.parseInt(pathArray[i]);
+ childNumber = new ChildNumber(number, false);
+ }
+ dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber);
+ }
+ ECKeyPair keyPair = ECKeyPair.create(dkKey.getPrivKeyBytes());
+ return keyPair;
+ }
+
+
+
+ /**
+ * 通过路径和种子获取私钥对
+ */
+ public static DeterministicKey getPrivateBySeed(String path, DeterministicSeed ds) {
+ String[] pathArray = path.split("/");
+ byte[] seedBytes = ds.getSeedBytes();
+ if (seedBytes == null)
+ return null;
+ DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes);
+ for (int i = 1; i < pathArray.length; i++) {
+ ChildNumber childNumber;
+ if (pathArray[i].endsWith("'")) {
+ int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1));
+ childNumber = new ChildNumber(number, true);
+ } else {
+ int number = Integer.parseInt(pathArray[i]);
+ childNumber = new ChildNumber(number, false);
+ }
+ dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber);
+ }
+// ECKeyPair keyPair = ECKeyPair.create(dkKey.getPrivKeyBytes());
+ return dkKey;
+ }
+
+
+
+ /**
+ * 通过助记词生成种子
+ * */
+ public static DeterministicSeed getDeterministicSeed(List list) {
+ try {
+ long creationTimeSeconds = System.currentTimeMillis() / 1000;
+ return new DeterministicSeed(list, null, "", creationTimeSeconds);
+ }catch (Exception e){}
+ return null;
+ }
+
+ /**
+ * 通过助记词生成Hex私钥
+ * */
+ public static String getPrivateKeyHex(List list) {
+ try {
+ long creationTimeSeconds = System.currentTimeMillis() / 1000;
+ DeterministicSeed seed = new DeterministicSeed(list, null, "", creationTimeSeconds);
+ ECKeyPair keyPair = getEcKeyPairByDeterministicSeed("m/44'/1'/0'/0/0", seed);
+ if (keyPair == null) return null;
+ ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey());
+ String hexPrivateKey = ecKey.getPrivateKeyAsHex();
+ return hexPrivateKey;
+ }catch (Exception e){}
+ return null;
+ }
+
+ /**
+ * 通过种子生成助记词字符串
+ */
+ public static String getMnemonic(DeterministicSeed ds) {
+ StringBuilder sb = new StringBuilder();
+ List mnemonicList = ds.getMnemonicCode();
+ for (int i = 0; mnemonicList != null && i < mnemonicList.size(); i++) {
+ sb.append(mnemonicList.get(i) + " ");
+ }
+ return sb.toString().trim();
+ }
+
+ /**判断地址的有效性*/
+ public static boolean isBTCValidAddress(String input) {
+ if (StringUtils.isEmpty(input))return false;
+ try {
+ NetworkParameters networkParameters = null;
+ networkParameters = MainNetParams.get();
+ Address address = Address.fromBase58(networkParameters, input);
+ if (address != null)
+ return true;
+ else
+ return false;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+
+}
diff --git a/sign-java-sdk/src/main/java/com/tokenview/utils/HexUtil.java b/sign-java-sdk/src/main/java/com/tokenview/utils/HexUtil.java
new file mode 100644
index 0000000..21bfb2d
--- /dev/null
+++ b/sign-java-sdk/src/main/java/com/tokenview/utils/HexUtil.java
@@ -0,0 +1,80 @@
+package com.tokenview.utils;
+
+/**
+ * @author zhaoda
+ * @date 2020/6/1.
+ * GitHub:
+ * email:
+ * description:
+ */
+public class HexUtil {
+ private static final char[] digits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ public static final byte[] emptybytes = new byte[0];
+
+ public HexUtil() {
+ }
+
+ public static String byte2HexStr(byte b) {
+ char[] buf = new char[]{'\u0000', digits[b & 15]};
+ b = (byte)(b >>> 4);
+ buf[0] = digits[b & 15];
+ return new String(buf);
+ }
+
+ public static String bytes2HexStr(byte[] bytes) {
+ if (bytes != null && bytes.length != 0) {
+ char[] buf = new char[2 * bytes.length];
+
+ for(int i = 0; i < bytes.length; ++i) {
+ byte b = bytes[i];
+ buf[2 * i + 1] = digits[b & 15];
+ b = (byte)(b >>> 4);
+ buf[2 * i + 0] = digits[b & 15];
+ }
+
+ return new String(buf);
+ } else {
+ return null;
+ }
+ }
+
+ public static byte hexStr2Byte(String str) {
+ return str != null && str.length() == 1 ? char2Byte(str.charAt(0)) : 0;
+ }
+
+ public static byte char2Byte(char ch) {
+ if (ch >= '0' && ch <= '9') {
+ return (byte)(ch - 48);
+ } else if (ch >= 'a' && ch <= 'f') {
+ return (byte)(ch - 97 + 10);
+ } else {
+ return ch >= 'A' && ch <= 'F' ? (byte)(ch - 65 + 10) : 0;
+ }
+ }
+
+ public static byte[] hexStr2Bytes(String str) {
+ if (str != null && !str.equals("")) {
+ byte[] bytes = new byte[str.length() / 2];
+
+ for(int i = 0; i < bytes.length; ++i) {
+ char high = str.charAt(i * 2);
+ char low = str.charAt(i * 2 + 1);
+ bytes[i] = (byte)(char2Byte(high) * 16 + char2Byte(low));
+ }
+
+ return bytes;
+ } else {
+ return emptybytes;
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ byte[] bytes = "Hello WebSocket World?".getBytes("gbk");
+ System.out.println(bytes2HexStr(bytes));
+ } catch (Exception var3) {
+ var3.printStackTrace();
+ }
+
+ }
+}
diff --git a/sign-java-sdk/src/main/java/com/tokenview/utils/HttpClientUtils.java b/sign-java-sdk/src/main/java/com/tokenview/utils/HttpClientUtils.java
new file mode 100644
index 0000000..0d6f2ff
--- /dev/null
+++ b/sign-java-sdk/src/main/java/com/tokenview/utils/HttpClientUtils.java
@@ -0,0 +1,370 @@
+package com.tokenview.utils;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.*;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.*;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.*;
+
+@Deprecated
+@Slf4j
+public final class HttpClientUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
+
+ public static String get(final String url, final Map params, final Map headerMap) {
+ HttpGet httpGet = null;
+ try {
+ URIBuilder ub = new URIBuilder(url);
+ List pairs = Lists.newArrayList();
+
+ if (params != null && !params.isEmpty()) {
+ for (Map.Entry entry : params.entrySet()) {
+ pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
+ }
+
+ ub.setParameters(pairs);
+ }
+ httpGet = new HttpGet(ub.build());
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ return execute(httpGet, headerMap);
+ }
+
+ public static String get(final String url, final Map headerMap) {
+ return get(url, null, headerMap);
+ }
+
+ public static JSONObject getReturnObject(final String url, final Map headerMap) {
+ String str = get(url, null, headerMap);
+ JSONObject json = null;
+ try {
+ json = JSONObject.parseObject(str);
+ } catch (Exception e) {
+ log.info("this resquest return not json object" + str);
+ json = new JSONObject();
+ }
+
+ return json;
+ }
+
+ public static JSONArray getReturnArray(final String url, final Map headerMap) {
+ String str = get(url, null, headerMap);
+ JSONArray json = null;
+ try {
+ json = JSONArray.parseArray(str);
+ } catch (Exception e) {
+ log.info("this resquest return not json array" + str);
+ json = new JSONArray();
+ }
+
+ return json;
+ }
+
+ public static String post(final String url, final Map params,
+ final Map headerMap) {
+ return post(url, params, headerMap, "utf-8");
+ }
+
+ public static String post(final String url, final Map params) {
+ return post(url, params, null, "utf-8");
+ }
+
+ public static String post(final String url, final Map params, final Map headerMap,
+ final String charset) {
+ final HttpPost request = new HttpPost(url);
+ if (params != null && params.size() > 0) {
+ List paramList = null;
+ final Set> entrySet = params.entrySet();
+ paramList = new ArrayList<>();
+ for (final Iterator> it = entrySet.iterator(); it.hasNext(); ) {
+ final Map.Entry entry = it.next();
+ final String key = entry.getKey();
+ final Object value = entry.getValue();
+ if (key != null && value != null) {
+ final NameValuePair nvp = new BasicNameValuePair(key, value.toString());
+ paramList.add(nvp);
+ }
+ }
+ try {
+ if (StringUtils.isEmpty(charset)) {
+ request.setEntity(new UrlEncodedFormEntity(paramList));
+ } else {
+ request.setEntity(new UrlEncodedFormEntity(paramList, Charset.forName(charset)));
+ }
+ } catch (final Exception e) {
+ logger.error("HttpClientUtils post", e);
+ return null;
+ }
+ }
+ return execute(request, headerMap);
+ }
+
+ public static String post(final String url, final HttpEntity entity, final Map headerMap) {
+ final HttpPost request = new HttpPost(url);
+ request.setEntity(entity);
+ return execute(request, headerMap);
+ }
+
+ public static String execute(final HttpRequestBase request, final Map headerMap) {
+ return execute(null, request, headerMap);
+ }
+
+ public static String execute(CloseableHttpClient httpclient, final HttpRequestBase request,
+ final Map headerMap) {
+ return execute(null, request, headerMap, 30000, 30000);
+ }
+
+ public static String execute(final HttpRequestBase request,
+ final Map headerMap, int socketTimeout, int connectTimeout) {
+ return execute(null, request, headerMap, socketTimeout, connectTimeout);
+ }
+
+ private static String execute(CloseableHttpClient httpclient, final HttpRequestBase request,
+ final Map headerMap, int socketTimeout, int connectTimeout) {
+ final StringBuffer log = new StringBuffer(
+ "HttpClientUtils execute method:" + request.getMethod() + " url:" + request.getURI());
+
+ boolean isClose = false;
+ if (httpclient == null) {
+ httpclient = HttpClients.createDefault();
+ isClose = true;
+ }
+ InputStream resStream = null;
+ InputStreamReader inputStreamReader = null;
+ BufferedReader br = null;
+ String result = "";
+
+ if (headerMap != null && headerMap.size() > 0) {
+ final Iterator iterator = headerMap.keySet().iterator();
+ while (iterator.hasNext()) {
+ final String key = iterator.next();
+ request.setHeader(key, headerMap.get(key));
+ }
+ }
+
+ try {
+ final RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(
+ connectTimeout)
+ .build();
+ request.setConfig(requestConfig);
+ final CloseableHttpResponse response = httpclient.execute(request);
+
+ try {
+
+ final HttpEntity entity = response.getEntity();
+
+ if (entity != null) {
+ resStream = entity.getContent();
+ try {
+ inputStreamReader = new InputStreamReader(resStream);
+ br = new BufferedReader(inputStreamReader);
+ final StringBuffer resBuffer = new StringBuffer();
+ String resTemp = "";
+ while ((resTemp = br.readLine()) != null) {
+ resBuffer.append(resTemp);
+ }
+ result = resBuffer.toString();
+ } finally {
+ if (br != null) {
+ br.close();
+ }
+ if (inputStreamReader != null) {
+ inputStreamReader.close();
+ }
+ if (resStream != null) {
+ resStream.close();
+ }
+ }
+ }
+ } finally {
+ response.close();
+ }
+ } catch (final Exception e) {
+ request.abort();
+ logger.error(log.toString(), e);
+ } finally {
+ request.abort();
+ try {
+ if (isClose) {
+ httpclient.close();
+ }
+ } catch (final IOException e) {
+ logger.error(log.toString(), e);
+ }
+ }
+ return result;
+ }
+
+ public static JSONObject post(String url, JSONObject params, Map header) {
+ try {
+
+ //创建post方式请求对象
+ HttpPost httpPost = new HttpPost(url);
+ if (header != null) {
+ for (Map.Entry entry : header.entrySet()) {
+ httpPost.setHeader(entry.getKey(), entry.getValue());
+ }
+ } else {
+ //设置header信息
+ httpPost.setHeader("Content-type", "application/json;charset=utf-8");
+ httpPost.setHeader("Accept", "application/json;charset=utf-8");
+ }
+
+ //
+ StringEntity requestEntity = new StringEntity(
+ params.toJSONString(),
+ ContentType.APPLICATION_JSON);
+ httpPost.setEntity(requestEntity);
+
+ log.debug("请求地址:" + url);
+ log.debug("请求参数:" + params.toJSONString());
+
+ return JSONObject.parseObject(send(httpPost, "UTF-8"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ public static String httpsGet(String url, Map header) {
+ try {
+ //创建post方式请求对象
+ HttpGet httpGet = new HttpGet(url);
+
+ if (header != null) {
+ for (Map.Entry entry : header.entrySet()) {
+ httpGet.setHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ //设置header信息
+ httpGet.setHeader("Content-type", "application/json;charset=utf-8");
+ httpGet.setHeader("Accept", "application/json;charset=utf-8");
+
+ log.debug("请求地址:" + url);
+
+ return send(httpGet, "UTF-8");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
+ SSLContext sc = SSLContext.getInstance("TLSv1.2");
+
+ // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
+ X509TrustManager trustManager = new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(
+ java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
+ String paramString) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(
+ java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
+ String paramString) throws CertificateException {
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ };
+
+ sc.init(null, new TrustManager[] {trustManager}, null);
+ return sc;
+ }
+
+ public static String send(HttpRequestBase requestBase, String encoding)
+ throws KeyManagementException, NoSuchAlgorithmException, IOException {
+ String body = "";
+ //采用绕过验证的方式处理https请求
+ SSLContext sslcontext = createIgnoreVerifySSL();
+
+ // 设置协议http和https对应的处理socket链接工厂的对象
+ Registry socketFactoryRegistry = RegistryBuilder.create()
+ .register("http", PlainConnectionSocketFactory.INSTANCE)
+ .register("https", new SSLConnectionSocketFactory(sslcontext))
+ .build();
+ PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+ HttpClients.custom().setConnectionManager(connManager);
+
+ //创建自定义的httpclient对象
+ CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).setSSLHostnameVerifier(
+ new TrustAnyHostnameVerifier()).build();
+
+ //CloseableHttpClient client = HttpClients.createDefault();
+
+ //执行请求操作,并拿到结果(同步阻塞)
+ CloseableHttpResponse response = client.execute(requestBase);
+ //获取结果实体
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ //按指定编码转换结果实体为String类型
+ body = EntityUtils.toString(entity, encoding);
+ }
+ EntityUtils.consume(entity);
+ //释放链接
+ response.close();
+ client.close();
+ connManager.close();
+ return body;
+ }
+
+ private static class TrustAnyHostnameVerifier implements HostnameVerifier {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ }
+
+ public static String put(final String url, final HttpEntity entity, final Map headerMap) {
+ final HttpPut request = new HttpPut(url);
+ request.setEntity(entity);
+ return execute(request, headerMap);
+ }
+
+ public static String put(final String url, final Map headerMap) {
+ final HttpPut request = new HttpPut(url);
+ return execute(request, headerMap);
+ }
+
+}
diff --git a/sign-java-sdk/src/main/java/com/tokenview/utils/HttpUtil.java b/sign-java-sdk/src/main/java/com/tokenview/utils/HttpUtil.java
new file mode 100644
index 0000000..f4a96f9
--- /dev/null
+++ b/sign-java-sdk/src/main/java/com/tokenview/utils/HttpUtil.java
@@ -0,0 +1,55 @@
+package com.tokenview.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class HttpUtil {
+
+ private String get(String url) {
+ return HttpClientUtils.get(url, new HashMap<>());
+ }
+
+ public JSONObject getTransactionDetail(String tx){
+ StringBuffer url = new StringBuffer("https://chain.api.btc.com/v3/tx/");
+ url.append(tx);
+ url.append("?verbose=3");
+ String result = null;
+ try {
+ result = get(url.toString());
+ } catch (Exception e) {
+ log.info(e.getMessage(), e);
+ }
+ return JSONObject.parseObject(result);
+ }
+
+ public JSONArray getUnspent(String txid,List addrList){
+ JSONObject result =new HttpUtil().getTransactionDetail(txid).getJSONObject("data");
+ long height =result.getLong("block_height");
+ JSONArray outputsArray = result.getJSONArray("outputs");
+ JSONArray unspents = new JSONArray();
+ int index =0;
+ for (Object o : outputsArray){
+ Object io = JSONObject.parseObject(o.toString()).get("addresses");
+ String address = String.valueOf(io).replace("[\"","").replace("\"]","");
+ if (addrList.contains(address)){
+ JSONObject txJson = JSONObject.parseObject(o.toString());
+ txJson.put("txid",txid);
+ txJson.put("tx_output_n",index);
+ txJson.put("block_height",height);
+ unspents.add(txJson);
+ }
+ index++;
+ }
+ log.info(JSON.toJSONString(unspents));
+ return unspents;
+ }
+}
diff --git a/sign-java-sdk/src/test/java/com/tokenview/sign/test/BTCSignTest.java b/sign-java-sdk/src/test/java/com/tokenview/sign/test/BTCSignTest.java
new file mode 100644
index 0000000..0ece12d
--- /dev/null
+++ b/sign-java-sdk/src/test/java/com/tokenview/sign/test/BTCSignTest.java
@@ -0,0 +1,76 @@
+package com.tokenview.sign.test;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.tokenview.sign.btc.BTCSign;
+import com.tokenview.utils.HttpUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+public class BTCSignTest {
+
+ @Test
+ public void testGetUnspent(){
+ String txid = "13c6235ee5e6403606f1539bc872813ac14a90521da6248ffbf63913a8675573";
+ List addrList = new ArrayList<>();
+ addrList.add("1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ");
+ JSONArray unspents =new HttpUtil().getUnspent(txid,addrList);
+ log.info(JSON.toJSONString(unspents));
+ }
+
+
+ @Test
+ public void testBTCSign(){
+ //unspent所在txid和所在地址
+ String txid = "6680c65d3b1f4ab61b7096441a257de51f8bab48d0dca2f76080891ad9b0796a";
+ List addrList = new ArrayList<>();
+ addrList.add("1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ");
+ //可自行设置多个输出地址和金额,找零地址和金额
+ JSONArray unspents =new HttpUtil().getUnspent(txid,addrList);
+ long inputAmount =unspents
+ .stream()
+ .mapToLong(o->JSONObject.parseObject(o.toString()).getLong("value"))
+ .sum();
+
+ JSONArray outputs = new JSONArray();
+ JSONObject outputTo = new JSONObject();
+ outputTo.put("address","16SzvWdCrYsVsMuRp43TfqvGvibBah7s17");
+ outputTo.put("amount",10000);
+ outputs.add(outputTo);
+ long outputToAmount = outputs
+ .stream()
+ .mapToLong(o -> JSONObject.parseObject(o.toString()).getLong("amount"))
+ .sum();
+ long outputChangeAmount = inputAmount - outputToAmount;
+ //input金额不足输出和找零返回不签名
+ if (outputChangeAmount<=0){
+ return;
+ }
+ JSONObject outputChange = new JSONObject();
+ outputChange.put("address","1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ");
+ outputChange.put("amount",outputChangeAmount);
+
+ outputs.add(outputChange);
+
+ //找零金额小于等于手续费返回不签名
+ long fee = (unspents.size() + outputs.size() * 2) * 148 - 10;
+ if (outputChangeAmount <= fee) {
+ return;
+ }
+
+ String signature = new BTCSign().signBTCTransaction("L2xigpefbyesCnzR5hJDFxKPD4A2qSuNHiz4utWnqEovhownw8U2",unspents,outputs);
+ log.info(signature);
+ }
+
+ @Test
+ public void testGetAddress(){
+ log.info(new BTCSign().getAddress("d71405cd1c95271e4c17569494100856d9e8706e081702ec5ec91a5b20ce1957"));
+ }
+
+
+}
diff --git a/sign-java-sdk/src/test/java/com/tokenview/sign/test/ETHSignTest.java b/sign-java-sdk/src/test/java/com/tokenview/sign/test/ETHSignTest.java
new file mode 100644
index 0000000..8f18b52
--- /dev/null
+++ b/sign-java-sdk/src/test/java/com/tokenview/sign/test/ETHSignTest.java
@@ -0,0 +1,51 @@
+package com.tokenview.sign.test;
+
+import com.tokenview.sign.eth.ETHSign;
+import com.tokenview.utils.BTCWalletUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+public class ETHSignTest {
+
+ @Test
+ public void testGetPrivateKeyFromStrList() {
+ List stringList = new ArrayList();
+ stringList.add("gym");
+ stringList.add("please");
+ stringList.add("sauce");
+ stringList.add("elephant");
+ stringList.add("trap");
+ stringList.add("bag");
+ stringList.add("logic");
+ stringList.add("okay");
+ stringList.add("impulse");
+ stringList.add("slogan");
+ stringList.add("goose");
+ stringList.add("birth");
+ BTCWalletUtil.loadWalletByMnemonic("eth",stringList,",","");
+ }
+
+ @Test
+ public void testGetAddress() {
+ String address = new ETHSign().getAddress("b71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f");
+ log.info(address);
+ }
+
+ @Test
+ public void testETHSign() {
+
+ String sinature = new ETHSign().signETHTransaction(
+ "0xb71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f",
+ "0x9Ae75431335d2e70f8DB0b35F6C179a43756f78e",
+ "1",
+ 78500000000L,
+ 21000L,
+ 80000000000L);
+ log.info(sinature);
+ }
+
+}