├── LICENSE ├── README.md ├── api-demo.iml ├── api-java-sdk ├── api-java-sdk.iml ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── tokenview │ │ └── api │ │ ├── client │ │ ├── APIClient.java │ │ ├── APICredentials.java │ │ ├── APIHttpClient.java │ │ ├── APIRetrofit.java │ │ └── ApiHttp.java │ │ ├── config │ │ └── APIConfiguration.java │ │ ├── constant │ │ └── APIConstants.java │ │ ├── enums │ │ ├── CharsetEnum.java │ │ ├── ContentTypeEnum.java │ │ ├── I18nEnum.java │ │ └── ResultCode.java │ │ ├── exception │ │ └── APIException.java │ │ ├── result │ │ └── HttpResult.java │ │ └── service │ │ ├── base │ │ ├── BaseService.java │ │ └── Impl │ │ │ ├── BaseAPI.java │ │ │ └── BaseServiceImpl.java │ │ └── wallet │ │ ├── WalletService.java │ │ └── impl │ │ ├── WalletAPI.java │ │ └── WalletServiceImpl.java │ └── test │ └── java │ └── com │ └── tokenview │ └── api │ └── test │ ├── base │ ├── BaseAPITest.java │ └── BaseConfig.java │ ├── services │ ├── ServicesAPITest.java │ └── ServicesConfig.java │ └── wallet │ ├── WalletAPITest.java │ └── WalletConfig.java ├── pom.xml └── sign-java-sdk ├── pom.xml ├── sign-java-sdk.iml └── src ├── main └── java │ └── com │ └── tokenview │ ├── account │ └── AddressUtil.java │ ├── bean │ └── WalletBean.java │ ├── enums │ ├── Coin.java │ └── Version.java │ ├── params │ ├── DashParams.java │ ├── DogeParams.java │ └── LitecoinParams.java │ ├── sign │ ├── btc │ │ └── BTCSign.java │ └── eth │ │ └── ETHSign.java │ └── utils │ ├── BTCWalletUtil.java │ ├── ECKeyUtil.java │ ├── HexUtil.java │ ├── HttpClientUtils.java │ └── HttpUtil.java └── test └── java └── com └── tokenview └── sign └── test ├── BTCSignTest.java └── ETHSignTest.java /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 tokenview-hub 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The Tokenview api-demo Project 2 | === 3 | * Tokenview signature and api program implementation in Java. 4 | 5 | Features 6 | --- 7 | * 120+ blockchains ,100B+ transactions ,20B+ addresses ,coin markets ,statistical information are supported 8 | * Demo code are mainly used for wallet app now,private key is kept by the developer to prevent leakage during transmission 9 | * Main crypto currency offline signature is supported 10 | * Transaction-broadcasting is supported 11 | * Fully Java ready ,with definition files and full Java source and Springboot 2.0 12 | * MIT License (including ALL dependencies) ;completely open source to do with as you please 13 | 14 | Launch your application 15 | --- 16 | * Get apikey here: https://services.tokenview.io 17 | * 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 18 | * Check postman document and start your application : https://documenter.getpostman.com/view/5728777/SVSEvX8k?version=latest 19 | 20 | Documentation 21 | --- 22 | * Official site: https://services.tokenview.io 23 | * Multi-chain Blockchain Explorer site: https://tokenview.io 24 | * Postman document: https://documenter.getpostman.com/view/5728777/SVSEvX8k?version=latest 25 | 26 | License 27 | --- 28 | * MIT License (including all dependencies). 29 | -------------------------------------------------------------------------------- /api-demo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /api-java-sdk/api-java-sdk.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /api-java-sdk/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | api-demo 7 | com.tokenview 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | com.tokenview 13 | api-java-sdk 14 | 1.0.0 15 | 16 | 17 | 18 | com.tokenview 19 | sign-java-sdk 20 | 1.0.0 21 | 22 | 23 | io.netty 24 | netty-all 25 | 4.1.36.Final 26 | 27 | 28 | com.squareup.okhttp3 29 | okhttp 30 | 3.10.0 31 | 32 | 33 | com.squareup.retrofit2 34 | retrofit 35 | 2.3.0 36 | 37 | 38 | org.slf4j 39 | slf4j-log4j12 40 | 1.8.0-beta2 41 | 42 | 43 | org.springframework 44 | spring-context 45 | 5.1.5.RELEASE 46 | 47 | 48 | com.squareup.retrofit2 49 | converter-scalars 50 | 2.3.0 51 | 52 | 53 | com.squareup.retrofit2 54 | converter-gson 55 | 2.3.0 56 | 57 | 58 | com.squareup.retrofit2 59 | adapter-rxjava 60 | 2.3.0 61 | 62 | 63 | org.apache.commons 64 | commons-lang3 65 | 3.7 66 | 67 | 68 | commons-collections 69 | commons-collections 70 | 3.2.2 71 | 72 | 73 | ch.qos.logback 74 | logback-classic 75 | 1.2.3 76 | 77 | 78 | com.google.guava 79 | guava 80 | 27.1-jre 81 | 82 | 83 | commons-codec 84 | commons-codec 85 | 1.12 86 | 87 | 88 | org.apache.commons 89 | commons-compress 90 | 1.18 91 | 92 | 93 | junit 94 | junit 95 | 4.12 96 | test 97 | 98 | 99 | org.projectlombok 100 | lombok 101 | 1.18.4 102 | 103 | 104 | com.fasterxml.jackson.core 105 | jackson-databind 106 | 2.9.5 107 | 108 | 109 | commons-beanutils 110 | commons-beanutils 111 | 1.9.3 112 | 113 | 114 | commons-collections 115 | commons-collections 116 | 3.2.1 117 | 118 | 119 | commons-lang 120 | commons-lang 121 | 2.6 122 | 123 | 124 | commons-logging 125 | commons-logging 126 | 1.1.1 127 | 128 | 129 | net.sf.ezmorph 130 | ezmorph 131 | 1.0.6 132 | 133 | 134 | net.sf.json-lib 135 | json-lib 136 | 2.2.3 137 | jdk15 138 | 139 | 140 | org.springframework 141 | spring-web 142 | 5.0.9.RELEASE 143 | test 144 | 145 | 146 | jstl 147 | jstl 148 | 1.2 149 | test 150 | 151 | 152 | com.alibaba 153 | fastjson 154 | 1.2.12 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | org.apache.maven.plugins 163 | maven-compiler-plugin 164 | 165 | 1.8 166 | 1.8 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/client/APIClient.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.client; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.tokenview.api.config.APIConfiguration; 5 | import com.tokenview.api.constant.APIConstants; 6 | import com.tokenview.api.exception.APIException; 7 | import com.tokenview.api.result.HttpResult; 8 | import okhttp3.OkHttpClient; 9 | import org.apache.commons.lang.StringUtils; 10 | import retrofit2.Call; 11 | import retrofit2.Response; 12 | import retrofit2.Retrofit; 13 | import java.io.IOException; 14 | 15 | 16 | /** 17 | * TokenView API Client 18 | * 19 | * @author Moilk 20 | * @version 1.0.0 21 | * @date 2021/1/20 11:13 22 | */ 23 | public class APIClient { 24 | 25 | private final APIConfiguration config; 26 | private final APICredentials credentials; 27 | private final OkHttpClient client; 28 | private final Retrofit retrofit; 29 | private final ApiHttp apiHttp; 30 | /** 31 | * Initialize the apis client 32 | */ 33 | public APIClient(final APIConfiguration config) { 34 | if (config == null || StringUtils.isEmpty(config.getEndpoint())) { 35 | throw new RuntimeException("The APIClient params can't be empty."); 36 | } 37 | this.config = config; 38 | this.credentials = new APICredentials(config); 39 | this.client = new APIHttpClient(config, this.credentials).client(); 40 | this.retrofit = new APIRetrofit(config, this.client).retrofit(); 41 | this.apiHttp = new ApiHttp(config, this.client); 42 | } 43 | 44 | /** 45 | * Initialize the retrofit operation service 46 | */ 47 | public T createService(final Class service) { 48 | return this.retrofit.create(service); 49 | } 50 | 51 | public ApiHttp getApiHttp() { 52 | return this.apiHttp; 53 | } 54 | 55 | /** 56 | * Synchronous send request 57 | */ 58 | //解析 59 | public T executeSync(final Call call){ 60 | try { 61 | 62 | final Response response = call.execute(); 63 | 64 | //获取状态码 65 | final int status = response.code(); 66 | //获取错误信息 67 | final String message = new StringBuilder().append(response.code()).append(" / ").append(response.message()).toString(); 68 | //响应成功 69 | if (response.isSuccessful()) { 70 | return response.body(); 71 | } else if (APIConstants.resultStatusArray.contains(status)) { 72 | final HttpResult result = JSON.parseObject(new String(response.errorBody().bytes()), HttpResult.class); 73 | if(result.getCode() == 0 && result.getMessage() == null){ 74 | throw new APIException(result.getErrorCode(),result.getErrorMessage()); 75 | }else{ 76 | throw new APIException(result.getCode(), result.getMessage()); 77 | } 78 | } else { 79 | throw new APIException(message); 80 | } 81 | } catch (final IOException e) { 82 | throw new APIException("APIClient executeSync exception.", e); 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/client/APICredentials.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.client; 2 | 3 | import com.tokenview.api.config.APIConfiguration; 4 | 5 | /** 6 | * API Credentials 7 | * 8 | * @author Moilk 9 | * @version 1.0.0 10 | * @date 2021/1/18 12:24 11 | */ 12 | public class APICredentials { 13 | public String getApiKey() { 14 | return apiKey; 15 | } 16 | 17 | public void setApiKey(String apiKey) { 18 | this.apiKey = apiKey; 19 | } 20 | 21 | /** 22 | * The user's secret key provided by TokenView. 23 | */ 24 | private String apiKey; 25 | 26 | public APICredentials(APIConfiguration config) { 27 | super(); 28 | this.apiKey = config.getApiKey(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/client/APIHttpClient.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.client; 2 | 3 | import com.tokenview.api.config.APIConfiguration; 4 | import com.tokenview.api.constant.APIConstants; 5 | import okhttp3.OkHttpClient; 6 | import okhttp3.Request; 7 | import okhttp3.RequestBody; 8 | import okio.Buffer; 9 | 10 | import java.io.IOException; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | public class APIHttpClient { 14 | private final APIConfiguration config; 15 | private final APICredentials credentials; 16 | 17 | 18 | public APIHttpClient(final APIConfiguration config, final APICredentials credentials) { 19 | this.config = config; 20 | this.credentials = credentials; 21 | } 22 | 23 | public OkHttpClient client() { 24 | final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); 25 | clientBuilder.connectTimeout(this.config.getConnectTimeout(), TimeUnit.SECONDS); 26 | clientBuilder.readTimeout(this.config.getReadTimeout(), TimeUnit.SECONDS); 27 | clientBuilder.writeTimeout(this.config.getWriteTimeout(), TimeUnit.SECONDS); 28 | clientBuilder.retryOnConnectionFailure(this.config.isRetryOnConnectionFailure()); 29 | // clientBuilder.addInterceptor((Interceptor.Chain chain) -> { 30 | // final Request.Builder requestBuilder = chain.request().newBuilder(); 31 | // final String timestamp = DateUtils.getUnixTime(); 32 | // //打印首行时间戳 33 | //// System.out.println("时间戳timestamp={" + timestamp + "}"); 34 | //// 设置模拟盘请求头 35 | //// String simulated = "1"; 36 | // requestBuilder.headers(this.headers(chain.request(), timestamp)); 37 | // final Request request = requestBuilder.build(); 38 | // if (this.config.isPrint()) { 39 | // this.printRequest(request, timestamp); 40 | // } 41 | // return chain.proceed(request); 42 | // }); 43 | return clientBuilder.build(); 44 | } 45 | 46 | //返回请求路径url 47 | private String url(final Request request) { 48 | return request.url().toString(); 49 | } 50 | //将请求方法转变为大写,并返回 51 | private String method(final Request request) { 52 | return request.method().toUpperCase(); 53 | } 54 | //返回请求路径 55 | private String requestPath(final Request request) { 56 | String url = this.url(request); 57 | url = url.replace(this.config.getEndpoint(), APIConstants.EMPTY); 58 | String requestPath = url; 59 | if (requestPath.contains(APIConstants.QUESTION)) { 60 | requestPath = requestPath.substring(0, url.lastIndexOf(APIConstants.QUESTION)); 61 | } 62 | if(this.config.getEndpoint().endsWith(APIConstants.SLASH)){ 63 | requestPath = APIConstants.SLASH + requestPath; 64 | } 65 | return requestPath; 66 | } 67 | 68 | private String queryString(final Request request) { 69 | final String url = this.url(request); 70 | request.body(); 71 | //请求参数为空字符串 72 | String queryString = APIConstants.EMPTY; 73 | //如果URL中包含?即存在参数的拼接 74 | if (url.contains(APIConstants.QUESTION)) { 75 | queryString = url.substring(url.lastIndexOf(APIConstants.QUESTION) + 1); 76 | } 77 | return queryString; 78 | } 79 | 80 | private String body(final Request request) throws IOException { 81 | final RequestBody requestBody = request.body(); 82 | String body = APIConstants.EMPTY; 83 | if (requestBody != null) { 84 | final Buffer buffer = new Buffer(); 85 | requestBody.writeTo(buffer); 86 | body = buffer.readString(APIConstants.UTF_8); 87 | } 88 | return body; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/client/APIRetrofit.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.client; 2 | 3 | 4 | import com.tokenview.api.config.APIConfiguration; 5 | import okhttp3.OkHttpClient; 6 | import retrofit2.Retrofit; 7 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 8 | import retrofit2.converter.gson.GsonConverterFactory; 9 | import retrofit2.converter.scalars.ScalarsConverterFactory; 10 | 11 | public class APIRetrofit { 12 | private APIConfiguration config; 13 | private OkHttpClient client; 14 | 15 | public APIRetrofit(APIConfiguration config, OkHttpClient client) { 16 | this.config = config; 17 | this.client = client; 18 | } 19 | 20 | public Retrofit retrofit() { 21 | Retrofit.Builder builder = new Retrofit.Builder(); 22 | builder.client(this.client); 23 | builder.addConverterFactory(ScalarsConverterFactory.create()); 24 | builder.addConverterFactory(GsonConverterFactory.create()); 25 | builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create()); 26 | builder.baseUrl(this.config.getEndpoint()); 27 | return builder.build(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/client/ApiHttp.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.client; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.tokenview.api.config.APIConfiguration; 5 | import com.tokenview.api.constant.APIConstants; 6 | import com.tokenview.api.exception.APIException; 7 | import okhttp3.*; 8 | 9 | import java.io.IOException; 10 | import java.util.Date; 11 | 12 | public class ApiHttp { 13 | private OkHttpClient client; 14 | private APIConfiguration config; 15 | 16 | static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); 17 | 18 | public ApiHttp(APIConfiguration config, OkHttpClient client) { 19 | this.config = config; 20 | this.client = client; 21 | } 22 | 23 | private void printResponse(int status, String message, String body, boolean responseIsNotNull) { 24 | StringBuilder responseInfo = new StringBuilder(); 25 | responseInfo.append("\n\tResponse").append("(").append(new Date()).append("):"); 26 | if (responseIsNotNull) { 27 | responseInfo.append("\n\t\t").append("Status: ").append(status); 28 | responseInfo.append("\n\t\t").append("Message: ").append(message); 29 | responseInfo.append("\n\t\t").append("Response Body: ").append(body); 30 | } else { 31 | responseInfo.append("\n\t\t").append("\n\tRequest Error: response is null"); 32 | } 33 | } 34 | 35 | public String url(String url) { 36 | return new StringBuilder(this.config.getEndpoint()).append(url).toString(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/config/APIConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.config; 2 | 3 | import com.tokenview.api.constant.APIConstants; 4 | import com.tokenview.api.enums.I18nEnum; 5 | 6 | /** 7 | * API configuration information 8 | * 9 | * @author Moilk 10 | * @version 1.0.0 11 | * @date 2021/1/20 14:29 12 | */ 13 | public class APIConfiguration { 14 | 15 | /** 16 | * The user's api key provided by TokenView. 17 | */ 18 | private String apiKey; 19 | /** 20 | * Rest api endpoint url. 21 | */ 22 | private String endpoint; 23 | /** 24 | * Host connection timeout. 25 | */ 26 | private long connectTimeout; 27 | /** 28 | * The host reads the information timeout. 29 | */ 30 | private long readTimeout; 31 | /** 32 | * The host writes the information timeout. 33 | */ 34 | private long writeTimeout; 35 | /** 36 | * Failure reconnection, default true. 37 | */ 38 | private boolean retryOnConnectionFailure; 39 | /** 40 | * The print api information. 41 | */ 42 | private boolean print; 43 | /** 44 | * I18nEnum 45 | */ 46 | private I18nEnum i18n; 47 | 48 | public APIConfiguration() { 49 | this(null); 50 | } 51 | public APIConfiguration(String endpoint) { 52 | super(); 53 | this.apiKey = null; 54 | this.endpoint = endpoint; 55 | this.connectTimeout = APIConstants.TIMEOUT; 56 | this.readTimeout = APIConstants.TIMEOUT; 57 | this.writeTimeout = APIConstants.TIMEOUT; 58 | this.retryOnConnectionFailure = true; 59 | this.print = false; 60 | this.i18n = I18nEnum.ENGLISH; 61 | } 62 | 63 | public String getApiKey() { 64 | return apiKey; 65 | } 66 | 67 | public void setApiKey(String apiKey) { 68 | this.apiKey = apiKey; 69 | } 70 | 71 | public String getEndpoint() { 72 | return endpoint; 73 | } 74 | 75 | public void setEndpoint(String endpoint) { 76 | this.endpoint = endpoint; 77 | } 78 | 79 | public long getConnectTimeout() { 80 | return connectTimeout; 81 | } 82 | 83 | public void setConnectTimeout(long connectTimeout) { 84 | this.connectTimeout = connectTimeout; 85 | } 86 | 87 | public long getReadTimeout() { 88 | return readTimeout; 89 | } 90 | 91 | public void setReadTimeout(long readTimeout) { 92 | this.readTimeout = readTimeout; 93 | } 94 | 95 | public long getWriteTimeout() { 96 | return writeTimeout; 97 | } 98 | 99 | public void setWriteTimeout(long writeTimeout) { 100 | this.writeTimeout = writeTimeout; 101 | } 102 | 103 | public boolean isRetryOnConnectionFailure() { 104 | return retryOnConnectionFailure; 105 | } 106 | 107 | public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) { 108 | this.retryOnConnectionFailure = retryOnConnectionFailure; 109 | } 110 | 111 | public boolean isPrint() { 112 | return print; 113 | } 114 | 115 | public void setPrint(boolean print) { 116 | this.print = print; 117 | } 118 | 119 | public I18nEnum getI18n() { 120 | return i18n; 121 | } 122 | 123 | public void setI18n(I18nEnum i18n) { 124 | this.i18n = i18n; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/constant/APIConstants.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.constant; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.tokenview.api.enums.ContentTypeEnum; 5 | import okhttp3.MediaType; 6 | 7 | import java.nio.charset.Charset; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | public class APIConstants { 12 | /** 13 | * The default timeout is 30 seconds. 14 | */ 15 | public static final long TIMEOUT = 1000 * 30; 16 | /** 17 | * All requests and responses are application/json content type and follow typical HTTP response status codes for success and failure. 18 | */ 19 | public static final String CONTENT_TYPE = "Content-Type"; 20 | 21 | public static final String ACCEPT = "Accept"; 22 | 23 | public static final String COOKIE = "Cookie"; 24 | 25 | public static final String LOCALE = "locale="; 26 | 27 | public static final MediaType JSON = MediaType.parse(ContentTypeEnum.APPLICATION_JSON.contentType()); 28 | 29 | public static final Charset UTF_8 = Charset.forName("UTF-8"); 30 | 31 | public static final String QUESTION = "?"; 32 | 33 | public static final String EMPTY = ""; 34 | 35 | public static final JSONObject NOTHING = new JSONObject(); 36 | 37 | public static final List toStringTypeArray = Arrays.asList( 38 | "class java.lang.Long", 39 | "class java.lang.Integer", 40 | "long", 41 | "int"); 42 | public static final List toStringTypeDoubleArray = Arrays.asList( 43 | "class java.lang.Double", 44 | "double"); 45 | 46 | public static final List resultStatusArray = Arrays.asList( 47 | 400,401,429,500); 48 | 49 | public static final String BOOLEAN = "boolean"; 50 | public static final String IS = "is"; 51 | public static final String get = "get"; 52 | public static final char a = 'a'; 53 | public static final char z = 'z'; 54 | public static final String ZERO_STRING = "0"; 55 | public static final String DOUBLE_ZERO_STRING = "0.00"; 56 | 57 | public static final String DOT1 = "."; 58 | public static final String DOT2 = "\\."; 59 | public static final String E = "E"; 60 | public static final String e = "e"; 61 | public static final int DEFAULT_SCALE = 2; 62 | /** 63 | * 8900000000.000000000 64 | */ 65 | public static final String DOUBLE_END1 = "0+?$"; 66 | /** 67 | * 8900000000. 68 | */ 69 | public static final String DOUBLE_END2 = "[.]$"; 70 | 71 | /** 72 | * default cursor id 73 | */ 74 | public static final int ONE = 1; 75 | /** 76 | * max limit: 100 77 | */ 78 | public static final int HUNDRED = 100; 79 | 80 | public static final String HLINE = "-"; 81 | 82 | public static final String SLASH = "/"; 83 | } 84 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/enums/CharsetEnum.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.enums; 2 | 3 | /** 4 | * 5 | * @author Moilk 6 | * @version 1.0.0 7 | * @date 2020/1/18 13:00 8 | */ 9 | public enum CharsetEnum { 10 | 11 | UTF_8("UTF-8"), 12 | ISO_8859_1("ISO-8859-1"),; 13 | 14 | 15 | private String charset; 16 | 17 | CharsetEnum(String charset) { 18 | this.charset = charset; 19 | } 20 | 21 | public String charset() { 22 | return charset; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/enums/ContentTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.enums; 2 | 3 | /** 4 | * 5 | * @author Moilk 6 | * @version 1.0.0 7 | * @date 2020/1/18 13:00 8 | */ 9 | public enum ContentTypeEnum { 10 | 11 | APPLICATION_JSON("application/json"), 12 | APPLICATION_JSON_UTF8("application/json; charset=UTF-8"), 13 | // The server does not support types 14 | APPLICATION_FORM("application/x-www-form-urlencoded; charset=UTF-8"),; 15 | 16 | 17 | private String contentType; 18 | 19 | ContentTypeEnum(String contentType) { 20 | this.contentType = contentType; 21 | } 22 | 23 | public String contentType() { 24 | return contentType; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/enums/I18nEnum.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.enums; 2 | 3 | /** 4 | * I18nEnum 5 | * 6 | * @author Moilk 7 | * @version 1.0.0 8 | * @date 2020/1/18 13:00 9 | */ 10 | public enum I18nEnum { 11 | ENGLISH("en_US"), 12 | SIMPLIFIED_CHINESE("zh_CN"), 13 | TRADITIONAL_CHINESE("zh_HK"),; 14 | 15 | private String i18n; 16 | 17 | I18nEnum(String i18n) { 18 | this.i18n = i18n; 19 | } 20 | 21 | public String i18n() { 22 | return i18n; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/enums/ResultCode.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.enums; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * I18nEnum 8 | * 9 | * @author Moilk 10 | * @version 1.0.0 11 | * @date 2020/1/18 13:00 12 | */ 13 | public enum ResultCode { 14 | 15 | /* 成功状态码 */ 16 | SUCCESS(1, "成功"), 17 | NO_DATA(404, "无数据"), 18 | 19 | /* 参数错误:10001-19999 */ 20 | PARAM_IS_INVALID(10001, "参数无效"), 21 | PARAM_IS_BLANK(10002, "参数为空"), 22 | PARAM_TYPE_BIND_ERROR(10003, "参数类型错误"), 23 | PARAM_NOT_COMPLETE(10004, "参数缺失"), 24 | 25 | /* 用户中心错误:20001-29999*/ 26 | USER_NOT_LOGGED_IN(20001, "用户未登录"), 27 | USER_LOGIN_ERROR(20002, "账号不存在或密码错误"), 28 | USER_ACCOUNT_FORBIDDEN(20003, "账号已被禁用"), 29 | USER_NOT_EXIST(20004, "用户不存在"), 30 | USER_HAS_EXISTED(20005, "用户已存在"), 31 | USER_COLLECTION_EXISTED(20006, "用户收藏已存在"), 32 | USER_COLLECTION_SAVE_ERROR(20007, "用户收藏更新失败"), 33 | USER_COLLECTION_DEL_ERROR(20008, "用户收藏删除失败"), 34 | USER_COLLECTION_LOOK_ERROR(20008, "用户收藏查询失败"), 35 | 36 | /* 业务错误:30001-39999 */ 37 | //SPECIFIED_QUESTIONED_USER_NOT_EXIST(30001, "某业务出现问题"), 38 | 39 | /* 系统错误:40001-49999 */ 40 | SYSTEM_INNER_ERROR(40001, "系统繁忙,请稍后重试"), 41 | 42 | /* 数据错误:50001-599999 */ 43 | RESULE_DATA_NONE(50001, "数据未找到"), 44 | DATA_IS_WRONG(50002, "数据有误"), 45 | DATA_ALREADY_EXISTED(50003, "数据已存在"), 46 | 47 | /* 接口错误:60001-69999 */ 48 | INTERFACE_INNER_INVOKE_ERROR(60001, "内部系统接口调用异常"), 49 | INTERFACE_OUTTER_INVOKE_ERROR(60002, "外部系统接口调用异常"), 50 | INTERFACE_FORBID_VISIT(60003, "该接口禁止访问"), 51 | INTERFACE_ADDRESS_INVALID(60004, "接口地址无效"), 52 | INTERFACE_REQUEST_TIMEOUT(60005, "接口请求超时"), 53 | INTERFACE_EXCEED_LOAD(60006, "接口负载过高"), 54 | 55 | /* 权限错误:70001-79999 */ 56 | PERMISSION_NO_ACCESS(70001, "无访问权限"); 57 | 58 | 59 | private Integer code; 60 | 61 | private String message; 62 | 63 | ResultCode(Integer code, String message) { 64 | this.code = code; 65 | this.message = message; 66 | } 67 | 68 | public Integer code() { 69 | return this.code; 70 | } 71 | 72 | public String message() { 73 | return this.message; 74 | } 75 | 76 | public static String getMessage(String name) { 77 | for (ResultCode item : ResultCode.values()) { 78 | if (item.name().equals(name)) { 79 | return item.message; 80 | } 81 | } 82 | return name; 83 | } 84 | 85 | public static Integer getCode(String name) { 86 | for (ResultCode item : ResultCode.values()) { 87 | if (item.name().equals(name)) { 88 | return item.code; 89 | } 90 | } 91 | return null; 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return this.name(); 97 | } 98 | 99 | //校验重复的code值 100 | public static void main(String[] args) { 101 | ResultCode[] ApiResultCodes = ResultCode.values(); 102 | List codeList = new ArrayList(); 103 | for (ResultCode ApiResultCode : ApiResultCodes) { 104 | if (codeList.contains(ApiResultCode.code)) { 105 | System.out.println(ApiResultCode.code); 106 | } else { 107 | codeList.add(ApiResultCode.code()); 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/exception/APIException.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.exception; 2 | 3 | public class APIException extends RuntimeException { 4 | private int code; 5 | 6 | public APIException(String message) { 7 | super(message); 8 | } 9 | 10 | public APIException(int code, String message) { 11 | super(message); 12 | this.code = code; 13 | } 14 | 15 | 16 | public APIException(Throwable cause) { 17 | super(cause); 18 | } 19 | 20 | public APIException(String message, Throwable cause) { 21 | super(message, cause); 22 | } 23 | 24 | @Override 25 | public String getMessage() { 26 | if (this.code != 0) { 27 | return this.code + " : " + super.getMessage(); 28 | } 29 | return super.getMessage(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/result/HttpResult.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.result; 2 | 3 | public class HttpResult { 4 | private int code; 5 | private String message; 6 | private int errorCode; 7 | private String errorMessage; 8 | private String order_id; 9 | private Boolean result; 10 | 11 | public int getErrorCode() { 12 | return errorCode; 13 | } 14 | 15 | public void setErrorCode(int errorCode) { 16 | this.errorCode = errorCode; 17 | } 18 | 19 | public String getErrorMessage() { 20 | return errorMessage; 21 | } 22 | 23 | public void setErrorMessage(String errorMessage) { 24 | this.errorMessage = errorMessage; 25 | } 26 | 27 | public int getCode() { 28 | return code; 29 | } 30 | 31 | public void setCode(int code) { 32 | this.code = code; 33 | } 34 | 35 | public String getMessage() { 36 | return message; 37 | } 38 | 39 | public void setMessage(String message) { 40 | this.message = message; 41 | } 42 | 43 | public String getOrder_id() { 44 | return order_id; 45 | } 46 | 47 | public void setOrder_id(String order_id) { 48 | this.order_id = order_id; 49 | } 50 | 51 | public Boolean getResult() { 52 | return result; 53 | } 54 | 55 | public void setResult(Boolean result) { 56 | this.result = result; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return "\t\tResponse Body:{" + 62 | "code=" + code + 63 | ", message='" + message + '\'' + 64 | ", errorCode=" + errorCode + 65 | ", errorMessage='" + errorMessage + '\'' + 66 | ", order_id='" + order_id + '\'' + 67 | ", result=" + result + 68 | '}'; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/service/base/BaseService.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.service.base; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | public interface BaseService { 6 | 7 | //获取指定交易详情 8 | JSONObject getTransaction(String currency, String txid); 9 | 10 | //获取UTXO(类BTC)指定地址交易列表 11 | JSONObject getUTXOTransactionList(String currency, String address, String page, String size); 12 | 13 | //获取ACCOUNT(类ETH/TRX)指定地址交易列表 14 | JSONObject getACCOUNTTransactionList(String currency, String address, String page, String size); 15 | 16 | //获取UTXO(类BTC)指定地址余额 17 | JSONObject getUTXOAddressBalance(String currency, String address); 18 | 19 | //获取ACCOUNT(类ETH/TRX)指定地址余额 20 | JSONObject getACCOUNTAddressBalance(String currency, String address); 21 | 22 | //T获取ACCOUNT(ETH,ETC,NAS,NEO)指定地址信息 23 | JSONObject getACCOUNTAddressInfo(String currency, String address); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseAPI.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.service.base.Impl; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import retrofit2.Call; 5 | import retrofit2.http.GET; 6 | import retrofit2.http.Path; 7 | 8 | public interface BaseAPI { 9 | 10 | @GET("/tx/{currency}/{txid}") 11 | Call getTransaction(@Path("currency") String currency, @Path("txid") String txid); 12 | 13 | @GET("/address/{currency}/{address}/{page}/{size}") 14 | Call getTransactionList(@Path("currency") String currency, @Path("address") String address, 15 | @Path("page") String page, @Path("size") String size); 16 | 17 | @GET("/{currency}/address/normal/{address}/{page}/{size}") 18 | Call getACCOUNTTransactionList(@Path("currency") String currency, @Path("address") String address, 19 | @Path("page") String page, @Path("size") String size); 20 | 21 | @GET("/address/{currency}/{address}/1/1") 22 | Call getAddressBalance(@Path("currency") String currency, @Path("address") String address); 23 | 24 | @GET("/addr/b/{currency}/{address}") 25 | Call getACCOUNTAddressBalance(@Path("currency") String currency, @Path("address") String address); 26 | 27 | @GET("/{currency}/address/{address}") 28 | Call getACCOUNTAddressInfo(@Path("currency") String currency, @Path("address") String address); 29 | } 30 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/service/base/Impl/BaseServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.service.base.Impl; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.tokenview.api.client.APIClient; 5 | import com.tokenview.api.config.APIConfiguration; 6 | import com.tokenview.api.service.base.BaseService; 7 | 8 | public class BaseServiceImpl implements BaseService { 9 | 10 | private APIClient client; 11 | private BaseAPI api; 12 | 13 | public BaseServiceImpl(APIConfiguration config) { 14 | this.client = new APIClient(config); 15 | this.api = client.createService(BaseAPI.class); 16 | } 17 | 18 | @Override 19 | public JSONObject getTransaction(String currency, String txid){ 20 | return this.client.executeSync(this.api.getTransaction(currency,txid)); 21 | } 22 | 23 | @Override 24 | public JSONObject getUTXOTransactionList(String currency,String address,String page,String size){ 25 | return this.client.executeSync(this.api.getTransactionList(currency,address,page,size)); 26 | } 27 | 28 | @Override 29 | public JSONObject getACCOUNTTransactionList(String currency,String address,String page,String size){ 30 | return this.client.executeSync(this.api.getACCOUNTTransactionList(currency,address,page,size)); 31 | } 32 | 33 | @Override 34 | public JSONObject getUTXOAddressBalance(String currency,String address){ 35 | return this.client.executeSync(this.api.getAddressBalance(currency,address)); 36 | } 37 | 38 | @Override 39 | public JSONObject getACCOUNTAddressBalance(String currency,String address){ 40 | return this.client.executeSync(this.api.getACCOUNTAddressBalance(currency,address)); 41 | } 42 | 43 | @Override 44 | public JSONObject getACCOUNTAddressInfo(String currency,String address){ 45 | return this.client.executeSync(this.api.getACCOUNTAddressInfo(currency,address)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/service/wallet/WalletService.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.service.wallet; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | public interface WalletService { 6 | 7 | //发送ETH/BTC交易到对应区块链 8 | JSONObject sendRawTransaction(String currency, JSONObject jo); 9 | 10 | //获取ACCOUNT(类ETH/TRX)指定地址信息 11 | JSONObject getACCOUNTAddressNonce(String currency, JSONObject jo); 12 | 13 | //获取TRX签名前内容 14 | JSONObject getTRXCreateTransaction(JSONObject jo); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletAPI.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.service.wallet.impl; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import retrofit2.Call; 5 | import retrofit2.http.Body; 6 | import retrofit2.http.POST; 7 | import retrofit2.http.Path; 8 | 9 | public interface WalletAPI { 10 | 11 | @POST("/onchainwallet/{currency}") 12 | Call sendRawTransaction(@Path("currency") String currency, @Body JSONObject jsonObject); 13 | 14 | @POST("/onchainwallet/{currency}") 15 | Call getACCOUNTAddressNonce(@Path("currency") String currency, @Body JSONObject jsonObject); 16 | 17 | @POST("/onchainwallet/trx") 18 | Call getTRXCreateTransaction(@Body JSONObject jsonObject); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /api-java-sdk/src/main/java/com/tokenview/api/service/wallet/impl/WalletServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.service.wallet.impl; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.tokenview.api.client.APIClient; 5 | import com.tokenview.api.config.APIConfiguration; 6 | import com.tokenview.api.service.wallet.WalletService; 7 | 8 | public class WalletServiceImpl implements WalletService { 9 | 10 | private APIClient client; 11 | private WalletAPI api; 12 | 13 | public WalletServiceImpl(APIConfiguration config) { 14 | this.client = new APIClient(config); 15 | this.api = client.createService(WalletAPI.class); 16 | } 17 | 18 | @Override 19 | public JSONObject sendRawTransaction(String currency,JSONObject jsonObject){ 20 | return this.client.executeSync(this.api.sendRawTransaction(currency,jsonObject)); 21 | } 22 | 23 | @Override 24 | public JSONObject getACCOUNTAddressNonce(String currency,JSONObject jsonObject){ 25 | return this.client.executeSync(this.api.getACCOUNTAddressNonce(currency,jsonObject)); 26 | } 27 | 28 | @Override 29 | public JSONObject getTRXCreateTransaction(JSONObject jsonObject){ 30 | return this.client.executeSync(this.api.getTRXCreateTransaction(jsonObject)); 31 | } 32 | 33 | 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseAPITest.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.test.base; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.tokenview.api.service.base.BaseService; 5 | import com.tokenview.api.service.base.Impl.BaseServiceImpl; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | /** 10 | * TokenView API Test 11 | * 12 | * @author Moilk 13 | * @version 1.0.0 14 | * @date 2021/1/20 11:13 15 | */ 16 | public class BaseAPITest extends BaseConfig{ 17 | 18 | private BaseService baseService; 19 | 20 | @Before 21 | public void before() { 22 | config = config(); 23 | baseService = new BaseServiceImpl(config); 24 | } 25 | 26 | /** 27 | * 查看交易详情,支持类BTC,类ETH,TRX等tokenview支持的所有币的交易查询 28 | * GET /tx/{currency}/{txid} 29 | */ 30 | @Test 31 | public void testGetTransaction(){ 32 | JSONObject result = baseService.getTransaction("btc","6680c65d3b1f4ab61b7096441a257de51f8bab48d0dca2f76080891ad9b0796a"); 33 | toResultString("GetTransaction", result); 34 | } 35 | 36 | /** 37 | * 查看UTXO(类BTC)指定地址余额 38 | * GET /address/{currency}/{address}/{page}/{size} 39 | */ 40 | @Test 41 | public void testGetUTXOAddressBalance(){ 42 | JSONObject result = baseService.getUTXOAddressBalance("btc","1AqSbAsXh3zxE8Z61afpU65u4pxB9BBRcz"); 43 | toResultString("GetUTXOAddressBalance", result); 44 | } 45 | 46 | /** 47 | * 查看UTXO(类BTC)指定地址交易列表 48 | * GET /address/{currency}/{address}/{page}/{size} 49 | */ 50 | @Test 51 | public void testGetUTXOTransactionList(){ 52 | JSONObject result = baseService.getUTXOTransactionList("btc","1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ","1","50"); 53 | toResultString("GetUTXOTransactionList", result); 54 | } 55 | 56 | /** 57 | * 查看ACCOUNT(类ETH/TRX)指定地址余额 58 | * GET /address/{currency}/{address}/{page}/{size} 59 | */ 60 | @Test 61 | public void testGetACCOUNTAddressBalance(){ 62 | JSONObject result = baseService.getACCOUNTAddressBalance("eth","0xda9cacf6c13450bea275c33e83503fb705d27bbb"); 63 | toResultString("GetACCOUNTAddressBalance", result); 64 | } 65 | 66 | /** 67 | * 查看获取ACCOUNT(类ETH/TRX)指定地址交易列表 68 | * GET /{currency}/address/normal/{address}/{page}/{size} 69 | */ 70 | @Test 71 | public void testGetACCOUNTTransactionList(){ 72 | JSONObject result = baseService.getACCOUNTTransactionList("eth","0x58b6a8a3302369daec383334672404ee733ab239","1","50"); 73 | toResultString("GetACCOUNTTransactionList", result); 74 | } 75 | 76 | /** 77 | * 查看ACCOUNT(ETH,ETC,NAS,NEO)指定地址详细信息 78 | * GET /{currency}/address/{address} 79 | */ 80 | @Test 81 | public void getACCOUNTAddressInfo(){ 82 | JSONObject result = baseService.getACCOUNTAddressInfo("eth","0xda9cacf6c13450bea275c33e83503fb705d27bbb"); 83 | toResultString("GetACCOUNTAddressInfo", result); 84 | } 85 | 86 | /** 87 | * 获取账户类型(类eth)地址信息(nonce),目前支持ETH,ETC,NAS,NEO,其他币暂时不支持 88 | * 89 | */ 90 | @Test 91 | public void getACCOUNTAddressNonce(){ 92 | String nonce = baseService.getACCOUNTAddressInfo("eth","0xda9cacf6c13450bea275c33e83503fb705d27bbb") 93 | .getJSONObject("data") 94 | .getString("nonce"); 95 | toResultString("GetACCOUNTAddressNonce", nonce); 96 | } 97 | 98 | 99 | } 100 | -------------------------------------------------------------------------------- /api-java-sdk/src/test/java/com/tokenview/api/test/base/BaseConfig.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.test.base; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.tokenview.api.config.APIConfiguration; 5 | import com.tokenview.api.enums.I18nEnum; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | public class BaseConfig { 10 | public APIConfiguration config; 11 | 12 | public APIConfiguration config() { 13 | APIConfiguration config = new APIConfiguration(); 14 | 15 | config.setEndpoint("http://www.tokenview.com:8088/"); 16 | config.setApiKey("ab2ac254-b5b3-4b13-bdea-e5d9a12319d7"); 17 | 18 | config.setPrint(true); 19 | config.setI18n(I18nEnum.ENGLISH); 20 | 21 | return config; 22 | } 23 | 24 | public void toResultString(String flag, Object object) { 25 | StringBuilder stringBuilder = new StringBuilder(); 26 | stringBuilder.append(flag).append(":\n").append(JSON.toJSONString(object)); 27 | System.out.println(stringBuilder); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesAPITest.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.test.services; 2 | 3 | /** 4 | * TokenView API Test 5 | * 6 | * @author Moilk 7 | * @version 1.0.0 8 | * @date 2021/1/20 11:44 9 | */ 10 | public class ServicesAPITest extends ServicesConfig { 11 | } 12 | -------------------------------------------------------------------------------- /api-java-sdk/src/test/java/com/tokenview/api/test/services/ServicesConfig.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.test.services; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.tokenview.api.config.APIConfiguration; 5 | import com.tokenview.api.enums.I18nEnum; 6 | 7 | public class ServicesConfig { 8 | 9 | 10 | public APIConfiguration config; 11 | 12 | public APIConfiguration config() { 13 | APIConfiguration config = new APIConfiguration(); 14 | // apiKey,api注册成功后页面上有 15 | //config.setEndpoint("https://wallet.tokenview.com/"); 16 | config.setEndpoint("http://www.tokenview.com:8088/"); 17 | config.setApiKey("ab2ac254-b5b3-4b13-bdea-e5d9a12319d7"); 18 | 19 | config.setPrint(true); 20 | config.setI18n(I18nEnum.ENGLISH); 21 | 22 | return config; 23 | } 24 | 25 | public void toResultString(String flag, Object object) { 26 | StringBuilder stringBuilder = new StringBuilder(); 27 | stringBuilder.append(flag).append(":\n").append(JSON.toJSONString(object)); 28 | System.out.println(stringBuilder); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletAPITest.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.test.wallet; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.tokenview.api.service.wallet.WalletService; 6 | import com.tokenview.api.service.wallet.impl.WalletServiceImpl; 7 | import com.tokenview.sign.btc.BTCSign; 8 | import com.tokenview.sign.eth.ETHSign; 9 | import com.tokenview.utils.BTCWalletUtil; 10 | import com.tokenview.utils.HttpUtil; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Arrays; 16 | import java.util.List; 17 | 18 | /** 19 | * TokenView API Test 20 | * 21 | * @author Moilk 22 | * @version 1.0.0 23 | * @date 2021/1/20 16:09 24 | */ 25 | public class WalletAPITest extends WalletConfig { 26 | 27 | private WalletService walletservice; 28 | 29 | @Before 30 | public void before() { 31 | config = config(); 32 | walletservice = new WalletServiceImpl(config); 33 | } 34 | /**由助记词得到eckey+wif格式私钥+hex格式私钥,适用于类BTC币和类ETH币,详细见打印信息,请注意以下两点 35 | * 类BTC币请使用BTC_MAIN_PATH 36 | * 类ETH币请使用ETH_MAIN_PATH 37 | * 使用对的chainpath才能和目前市场主流钱包生成地址相同,否则不同!!!! 38 | * @Param List 39 | */ 40 | @Test 41 | public void getEckey(){ 42 | List stringList = new ArrayList(); 43 | stringList.add("gym"); 44 | stringList.add("please"); 45 | stringList.add("sauce"); 46 | stringList.add("elephant"); 47 | stringList.add("trap"); 48 | stringList.add("bag"); 49 | stringList.add("logic"); 50 | stringList.add("okay"); 51 | stringList.add("impulse"); 52 | stringList.add("slogan"); 53 | stringList.add("goose"); 54 | stringList.add("birth"); 55 | BTCWalletUtil.loadWalletByMnemonic("btc",stringList,"bc1q44elpv05mkdkp5qyd8fajcq2lrczpsats7zjgr","mywallet"); 56 | BTCWalletUtil.loadWalletByMnemonic("eth",stringList,"bc1q44elpv05mkdkp5qyd8fajcq2lrczpsats7zjgr","mywallet"); 57 | } 58 | 59 | /** 60 | * 创建账户类型(类eth)地址 61 | * @Param privateKey 62 | */ 63 | @Test 64 | public void createACCOUNTAddress(){ 65 | toResultString("CreateACCOUNTAddress", new ETHSign().getAddress("b71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f")); 66 | } 67 | 68 | /** 69 | * 创建UTXO(类BTC)地址 70 | * @Param privateKey 71 | */ 72 | @Test 73 | public void createUTXOAddress(){ 74 | toResultString("CreateUTXOAddress",new BTCSign().getAddress("ab4ff104eddcc43430e0afe9487f21e1033fdc4eca9448065593d49fbc5e6b53")); 75 | } 76 | 77 | 78 | /** 79 | * 使用私钥对账户类型(类eth)地址发交易进行签名,nonce调用BaseAPI获取,gasPrice和gasLimit可使用下面固定值约 $2/笔 80 | * @Param privateKey 81 | * @Param toAddress 82 | * @Param nonce 83 | * @Param gasPrice 84 | * @Param gasLimit 85 | * @Param amount 86 | */ 87 | @Test 88 | public void SignEthTransaction(){ 89 | toResultString("SignEthTransaction", new ETHSign().signETHTransaction( 90 | "0xb71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f", 91 | "0x9Ae75431335d2e70f8DB0b35F6C179a43756f78e", 92 | "1", 93 | 78500000000L, 94 | 21000L, 95 | 100000000L)); 96 | } 97 | 98 | /** 99 | * 使用私钥对UTXO类型(类BTC)地址发交易进行签名,包含获取unspent并组装交易过程,暂不支持隔离见证bech32地址 100 | * @Param txid 101 | * @Param inputAddress(可若干个) 102 | * @Param toAddress(可若干个) 103 | * @Param toAmount(可若干个) 104 | * @Param changeAddress 105 | * @Param privateKeyWif(privateKeyHex也可只要能生成Eckey,本次测试用wif格式) 106 | */ 107 | @Test 108 | public void SignBTCTransaction(){ 109 | //unspent所在txid和所在地址 110 | String txid = "6680c65d3b1f4ab61b7096441a257de51f8bab48d0dca2f76080891ad9b0796a"; 111 | String inputAddress="1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ"; 112 | String toAdddress = "3Kjn9rsoQPrHQXGCJjJuuqZe46JNAseN1t"; 113 | long toAmount = 10000; 114 | String changeAddress="1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ"; 115 | String privateKeyWIF = "L2xigpefbyesCnzR5hJDFxKPD4A2qSuNHiz4utWnqEovhownw8U2"; 116 | 117 | List addrList = new ArrayList<>(); 118 | addrList.add(inputAddress); 119 | //可自行设置多个输出地址和金额,找零地址和金额 120 | JSONArray unspents =new HttpUtil().getUnspent(txid,addrList); 121 | long inputAmount =unspents 122 | .stream() 123 | .mapToLong(o->JSONObject.parseObject(o.toString()).getLong("value")) 124 | .sum(); 125 | 126 | JSONArray outputs = new JSONArray(); 127 | JSONObject outputTo = new JSONObject(); 128 | outputTo.put("address",toAdddress); 129 | outputTo.put("amount",toAmount); 130 | outputs.add(outputTo); 131 | long outputToAmount = outputs 132 | .stream() 133 | .mapToLong(o -> JSONObject.parseObject(o.toString()).getLong("amount")) 134 | .sum(); 135 | long outputChangeAmount = inputAmount - outputToAmount; 136 | //input金额不足输出和找零返回不签名 137 | if (outputChangeAmount<=0){ 138 | return; 139 | } 140 | JSONObject outputChange = new JSONObject(); 141 | outputChange.put("address",changeAddress); 142 | outputChange.put("amount",outputChangeAmount); 143 | 144 | outputs.add(outputChange); 145 | 146 | //找零金额小于等于手续费返回不签名 147 | long fee = (unspents.size() + outputs.size() * 2) * 148 - 10; 148 | if (outputChangeAmount <= fee) { 149 | return; 150 | } 151 | toResultString("SignBTCTransaction",new BTCSign().signBTCTransaction(privateKeyWIF,unspents,outputs)); 152 | } 153 | 154 | 155 | /** 156 | * 广播类btc/eth/etc交易上链,对应不同method,注意替换 157 | * POST /onchainwallet/{currency} 158 | * @Param method 159 | * @Param signature 160 | * @Param currency 161 | */ 162 | @Test 163 | public void testSendETHRawTransaction() { 164 | 165 | JSONObject jo =new JSONObject(); 166 | jo.put("jsonrpc","2.0"); 167 | jo.put("id","viewtoken"); 168 | jo.put("method","eth_sendRawTransaction"); 169 | jo.put("params", Arrays.asList("0xf86801851246f6f100825208949ae75431335d2e70f8db0b35f6c179a43756f78e8405f5e100801ca058b2130954d3b84918db5c0fc309dcc942b8656d88964a5f981a4a954bbb1221a0788b6b75afaea28d2e9178a6cea3d432983c10db1c778a1dcb6af009f5457701")); 170 | JSONObject onchainwallet = walletservice.sendRawTransaction("eth",jo); 171 | toResultString("SendRawTransaction", onchainwallet); 172 | } 173 | @Test 174 | public void testSendBTCRawTransaction(){ 175 | JSONObject jo =new JSONObject(); 176 | jo.put("jsonrpc","2.0"); 177 | jo.put("id","viewtoken"); 178 | jo.put("method","sendrawtransaction"); 179 | jo.put("params", Arrays.asList("01000000016a79b0d91a898060f7a2dcd048ab8b1fe57d251a4496701bb64a1f3b5dc68066010000006b483045022100f5c22019fdd167dfe16988cabbe31a4eeda609abfd8369612813cd510cadca5102201270c8dca6a6b7826162d7f5b00c7a479ad32505a55e958301473bdcab72079f8121033efaa795ed22b1531127a3fd5b6e72031f6a7f4370fb67367768054ef011def0ffffffff02102700000000000017a914c64907144796b4177d6b5809c388c437385db4bb879ab00000000000001976a914d2ed73cd81bb2d516411c47a8ddb02ae5f2e7d0188ac00000000")); 180 | JSONObject onchainwallet = walletservice.sendRawTransaction("btc",jo); 181 | toResultString("SendRawTransaction", onchainwallet); 182 | } 183 | 184 | 185 | 186 | 187 | } 188 | -------------------------------------------------------------------------------- /api-java-sdk/src/test/java/com/tokenview/api/test/wallet/WalletConfig.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.api.test.wallet; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.tokenview.api.config.APIConfiguration; 5 | import com.tokenview.api.enums.I18nEnum; 6 | 7 | public class WalletConfig { 8 | 9 | public APIConfiguration config; 10 | 11 | public APIConfiguration config() { 12 | APIConfiguration config = new APIConfiguration(); 13 | // apiKey,api注册成功后页面上有 14 | config.setEndpoint("https://wallet.tokenview.com/"); 15 | config.setApiKey("ab2ac254-b5b3-4b13-bdea-e5d9a12319d7"); 16 | 17 | config.setPrint(true); 18 | config.setI18n(I18nEnum.ENGLISH); 19 | 20 | return config; 21 | } 22 | 23 | public void toResultString(String flag, Object object) { 24 | StringBuilder stringBuilder = new StringBuilder(); 25 | stringBuilder.append(flag).append(":\n").append(JSON.toJSONString(object)); 26 | System.out.println(stringBuilder); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.tokenview 8 | api-demo 9 | pom 10 | 1.0.0 11 | 12 | sign-java-sdk 13 | api-java-sdk 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /sign-java-sdk/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | api-demo 7 | com.tokenview 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | com.tokenview 13 | sign-java-sdk 14 | 1.0.0 15 | 16 | 17 | 18 | cash.bitcoinj 19 | bitcoinj-tools 20 | 0.14.5.2 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.web3j 29 | core 30 | 3.0.1 31 | 32 | 33 | jnr-ffi 34 | com.github.jnr 35 | 36 | 37 | okio 38 | com.squareup.okio 39 | 40 | 41 | bcprov-jdk15on 42 | org.bouncycastle 43 | 44 | 45 | slf4j-api 46 | org.slf4j 47 | 48 | 49 | okhttp 50 | com.squareup.okhttp3 51 | 52 | 53 | jackson-databind 54 | com.fasterxml.jackson.core 55 | 56 | 57 | 58 | 59 | org.web3j 60 | crypto 61 | 4.2.0 62 | 63 | 64 | org.slf4j 65 | slf4j-log4j12 66 | 1.8.0-beta2 67 | 68 | 69 | org.springframework 70 | spring-context 71 | 5.1.5.RELEASE 72 | 73 | 74 | com.squareup.retrofit2 75 | converter-scalars 76 | 2.3.0 77 | 78 | 79 | com.squareup.retrofit2 80 | converter-gson 81 | 2.3.0 82 | 83 | 84 | com.squareup.retrofit2 85 | adapter-rxjava 86 | 2.3.0 87 | 88 | 89 | org.apache.commons 90 | commons-lang3 91 | 3.7 92 | 93 | 94 | ch.qos.logback 95 | logback-classic 96 | 1.2.3 97 | 98 | 99 | com.google.guava 100 | guava 101 | 27.1-jre 102 | 103 | 104 | commons-codec 105 | commons-codec 106 | 1.12 107 | 108 | 109 | org.apache.commons 110 | commons-compress 111 | 1.18 112 | 113 | 114 | org.projectlombok 115 | lombok 116 | 1.18.4 117 | 118 | 119 | com.fasterxml.jackson.core 120 | jackson-databind 121 | 2.9.5 122 | 123 | 124 | commons-beanutils 125 | commons-beanutils 126 | 1.9.3 127 | 128 | 129 | commons-collections 130 | commons-collections 131 | 3.2.1 132 | 133 | 134 | commons-logging 135 | commons-logging 136 | 1.1.1 137 | 138 | 139 | net.sf.ezmorph 140 | ezmorph 141 | 1.0.6 142 | 143 | 144 | com.alibaba 145 | fastjson 146 | 1.2.12 147 | 148 | 149 | net.sf.json-lib 150 | json-lib 151 | 2.2.3 152 | jdk15 153 | 154 | 155 | org.springframework 156 | spring-web 157 | 5.0.9.RELEASE 158 | test 159 | 160 | 161 | jstl 162 | jstl 163 | 1.2 164 | test 165 | 166 | 167 | junit 168 | junit 169 | 4.12 170 | test 171 | 172 | 173 | com.madgag.spongycastle 174 | prov 175 | 1.58.0.0 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | org.apache.httpcomponents 184 | httpclient 185 | 4.5.8 186 | 187 | 188 | org.bitcoincashj 189 | bitcoincashj-core 190 | 1.1.0-SNAPSHOT 191 | 192 | 193 | 194 | io.neow3j 195 | core 196 | 3.7.1 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | org.apache.maven.plugins 205 | maven-compiler-plugin 206 | 207 | 1.8 208 | 1.8 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /sign-java-sdk/sign-java-sdk.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/account/AddressUtil.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.account; 2 | 3 | import com.tokenview.bean.WalletBean; 4 | import com.tokenview.enums.Coin; 5 | import com.tokenview.params.DashParams; 6 | import com.tokenview.params.DogeParams; 7 | import com.tokenview.params.LitecoinParams; 8 | import com.tokenview.utils.ECKeyUtil; 9 | import org.bitcoinj.core.ECKey; 10 | import org.bitcoinj.core.NetworkParameters; 11 | import org.bitcoinj.params.MainNetParams; 12 | import org.bitcoinj.wallet.UnreadableWalletException; 13 | import org.web3j.crypto.ECKeyPair; 14 | import org.web3j.crypto.Keys; 15 | import org.web3j.utils.Numeric; 16 | 17 | public class AddressUtil { 18 | 19 | public static WalletBean generateAddress(String mnemonic, Coin coin) throws UnreadableWalletException { 20 | ECKeyPair keyPair = ECKeyUtil.generateEcKey(mnemonic, coin); 21 | ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey()); 22 | WalletBean wallet=new WalletBean(); 23 | wallet.setCoin_type(coin.getCoin()); 24 | NetworkParameters parameters=null; 25 | switch (coin){ 26 | case BTC: 27 | case BCH: 28 | case BSV: 29 | parameters= MainNetParams.get(); 30 | wallet.setAddress(ecKey.toAddress(parameters).toBase58()); 31 | wallet.setPrivateKey(ecKey.getPrivateKeyAsWiF(parameters)); 32 | break; 33 | case LTC: 34 | parameters= LitecoinParams.get(); 35 | wallet.setAddress(ecKey.toAddress(parameters).toBase58()); 36 | wallet.setPrivateKey(ecKey.getPrivateKeyAsWiF(parameters)); 37 | break; 38 | case DOGE: 39 | parameters= DogeParams.get(); 40 | wallet.setAddress(ecKey.toAddress(parameters).toBase58()); 41 | wallet.setPrivateKey(ecKey.getPrivateKeyAsWiF(parameters)); 42 | break; 43 | case DASH: 44 | parameters= DashParams.get(); 45 | wallet.setAddress(ecKey.toAddress(parameters).toBase58()); 46 | wallet.setPrivateKey(ecKey.getPrivateKeyAsWiF(parameters)); 47 | break; 48 | case ETH: 49 | case HT: 50 | case ETC: 51 | case PI: 52 | case WAN: 53 | case EM: 54 | String address = Keys.getAddress(keyPair); 55 | if(coin== Coin.EM){ 56 | address="EM"+address; 57 | }else{ 58 | address="0x"+address; 59 | } 60 | wallet.setAddress(address); 61 | String privateKey = Numeric.toHexStringNoPrefixZeroPadded(keyPair.getPrivateKey(), Keys.PRIVATE_KEY_LENGTH_IN_HEX); 62 | wallet.setPrivateKey(privateKey); 63 | break; 64 | case NEO: 65 | io.neow3j.crypto.ECKeyPair ecKeyPair= io.neow3j.crypto.ECKeyPair.create(keyPair.getPrivateKey()); 66 | wallet.setAddress(ecKeyPair.getAddress()); 67 | wallet.setPrivateKey(ecKeyPair.exportAsWIF()); 68 | break; 69 | default: 70 | break; 71 | } 72 | wallet.setMnemonic(mnemonic); 73 | return wallet; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/bean/WalletBean.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.bean; 2 | 3 | public class WalletBean { 4 | private String coin_type; 5 | private String mnemonic; 6 | private String address; 7 | private String keystore; 8 | private String privateKey; 9 | 10 | public String getCoin_type() { 11 | return coin_type; 12 | } 13 | 14 | public void setCoin_type(String coin_type) { 15 | this.coin_type = coin_type; 16 | } 17 | 18 | public String getMnemonic() { 19 | return mnemonic; 20 | } 21 | 22 | public void setMnemonic(String mnemonic) { 23 | this.mnemonic = mnemonic; 24 | } 25 | 26 | public String getAddress() { 27 | return address; 28 | } 29 | 30 | public void setAddress(String address) { 31 | this.address = address; 32 | } 33 | 34 | public String getKeystore() { 35 | return keystore; 36 | } 37 | 38 | public void setKeystore(String keystore) { 39 | this.keystore = keystore; 40 | } 41 | 42 | public String getPrivateKey() { 43 | return privateKey; 44 | } 45 | 46 | public void setPrivateKey(String privateKey) { 47 | this.privateKey = privateKey; 48 | } 49 | 50 | 51 | @Override 52 | public String toString() { 53 | return "WalletBean{" + 54 | "coin_type='" + coin_type + '\'' + 55 | ", mnemonic='" + mnemonic + '\'' + 56 | ", address='" + address + '\'' + 57 | ", keystore='" + keystore + '\'' + 58 | ", privateKey='" + privateKey + '\'' + 59 | '}'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/enums/Coin.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.enums; 2 | 3 | public enum Coin { 4 | BTC("BTC","m/44'/0'/0'/0/0"), 5 | BCH("BCH","m/44'/145'/0'/0/0"), 6 | BSV("BSV","m/44'/145'/0'/0/0"), 7 | 8 | LTC("LTC","m/44'/2'/0'/0/0"), 9 | DOGE("Doge","m/44'/3'/0'/0/0"), 10 | DASH("Dash","m/44'/5'/0'/0/0"), 11 | 12 | NEO("NEO","m/44'/888'/0'/0/0"), 13 | 14 | EM("EM","m/44'/60'/0'/0/0"), 15 | 16 | ETH("ETH","m/44'/60'/0'/0/0"), 17 | ETC("ETC","m/44'/61'/0'/0/0"), 18 | HT("HT","m/44'/60'/0'/0/0"), 19 | PI("PI","m/44'/60'/0'/0/0"), 20 | WAN("WAN","m/44'/5718350'/0'/0/0"); 21 | 22 | private String coin; 23 | private String path; 24 | Coin(String coin,String path){this.coin=coin;this.path=path;} 25 | 26 | public String getCoin(){return coin;} 27 | 28 | public String getPath(){return path;} 29 | } 30 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/enums/Version.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.enums; 2 | 3 | public enum Version { 4 | BTC(1); 5 | 6 | private Integer version; 7 | 8 | Version(Integer version) { 9 | this.version = version; 10 | } 11 | 12 | public Integer getVersion() { 13 | return version; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/params/DashParams.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.params; 2 | 3 | import org.bitcoinj.params.AbstractBitcoinNetParams; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * @author zhaoda 9 | * @date 2019/10/17. 10 | * GitHub: 11 | * email: 12 | * description: 13 | */ 14 | public class DashParams extends AbstractBitcoinNetParams { 15 | private static final Logger log = LoggerFactory.getLogger(DashParams.class); 16 | 17 | public static final int MAINNET_MAJORITY_WINDOW = 1000; 18 | public static final int MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED = 950; 19 | public static final int MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE = 750; 20 | 21 | public static final int MAINNET_MAJORITY_DIP0001_WINDOW = 4032; 22 | public static final int MAINNET_MAJORITY_DIP0001_THRESHOLD = 3226; 23 | 24 | public static final int p2shHeaderDash = 16; 25 | 26 | public static final int AddressHeaderDash = 76; 27 | 28 | public DashParams() { 29 | super(); 30 | p2shHeader = p2shHeaderDash; 31 | dumpedPrivateKeyHeader = 204; 32 | addressHeader = AddressHeaderDash; 33 | acceptableAddressCodes = new int[] { addressHeader, p2shHeader}; 34 | id = ID_MAINNET; 35 | interval = INTERVAL; 36 | 37 | } 38 | 39 | private static DashParams instance; 40 | public static synchronized DashParams get() { 41 | if (instance == null) { 42 | instance = new DashParams(); 43 | } 44 | return instance; 45 | } 46 | 47 | @Override 48 | public String getPaymentProtocolId() { 49 | return PAYMENT_PROTOCOL_ID_MAINNET; 50 | } 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/params/DogeParams.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.params; 2 | 3 | import org.bitcoinj.params.AbstractBitcoinNetParams; 4 | 5 | /** 6 | * @author zhaoda 7 | * @date 2019/10/18. 8 | * GitHub: 9 | * email: 10 | * description: 11 | */ 12 | public class DogeParams extends AbstractBitcoinNetParams { 13 | public static final String ID_DOGE_MAINNET = "org.dogecoin.production"; 14 | public DogeParams() { 15 | super(); 16 | p2shHeader = 22; 17 | dumpedPrivateKeyHeader = 158; 18 | addressHeader = 30; 19 | acceptableAddressCodes = new int[]{addressHeader, p2shHeader}; 20 | id = ID_DOGE_MAINNET; 21 | // interval = INTERVAL; 22 | // bip32HeaderPub = 0x02facafd; //The 4 byte header that serializes in base58 to "dgub". 23 | // bip32HeaderPriv = 0x02fac398; //The 4 byte header that serializes in base58 to "dgpv". 24 | } 25 | 26 | private static DogeParams instance; 27 | public static synchronized DogeParams get() { 28 | if (instance == null) { 29 | instance = new DogeParams(); 30 | } 31 | return instance; 32 | } 33 | 34 | @Override 35 | public String getPaymentProtocolId() { 36 | return "main"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/params/LitecoinParams.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.params; 2 | 3 | import org.bitcoinj.params.AbstractBitcoinNetParams; 4 | 5 | public class LitecoinParams extends AbstractBitcoinNetParams { 6 | 7 | /* 8 | 48 --> L.. addresses 9 | 50 --> the new M.. addresses 10 | Blockcypher doesn't support M address at the moment 11 | */ 12 | 13 | public LitecoinParams() { 14 | super(); 15 | p2shHeader = 5; 16 | dumpedPrivateKeyHeader = 176; 17 | addressHeader = 48; 18 | acceptableAddressCodes = new int[]{addressHeader, p2shHeader, 50}; 19 | id = "org.litecoin.production"; 20 | } 21 | 22 | private static LitecoinParams instance; 23 | public static synchronized LitecoinParams get() { 24 | if (instance == null) { 25 | instance = new LitecoinParams(); 26 | } 27 | return instance; 28 | } 29 | 30 | @Override 31 | public String getPaymentProtocolId() { 32 | return "main"; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/sign/btc/BTCSign.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.sign.btc; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.tokenview.enums.Version; 6 | import org.bitcoinj.core.*; 7 | import org.bitcoinj.params.MainNetParams; 8 | import org.bitcoinj.script.Script; 9 | import org.spongycastle.util.encoders.Hex; 10 | 11 | public class BTCSign { 12 | public String signBTCTransaction(String privateKey,JSONArray unspents,JSONArray outputs) { 13 | String hexString = ""; 14 | try { 15 | NetworkParameters params = MainNetParams.get(); 16 | DumpedPrivateKey priKey = DumpedPrivateKey.fromBase58(params,privateKey); 17 | ECKey ecKey = priKey.getKey(); 18 | System.out.println(ecKey.getPrivateKeyAsHex()); 19 | System.out.println(ecKey.getPublicKeyAsHex()); 20 | System.out.println(new String(ecKey.getPubKeyHash())); 21 | //构建交易体 22 | Transaction transaction = new Transaction(params); 23 | //交易的版本 默认的BTC,LTC ,DOGE,DASH 版本号是1, BCH BSV 版本号是:2; 24 | transaction.setVersion(Version.BTC.getVersion()); 25 | long fee = (unspents.size() + outputs.size() * 2) * 148 - 10; 26 | //添加转出到的地址列表和数量 27 | for(int i = 0;i inputParameters = new ArrayList<>(); 26 | inputParameters.add(new Address(toAddress)); 27 | inputParameters.add(new Uint256(0L));//转出数量 28 | List> outputParameters = new ArrayList<>(); 29 | //调用的合约的方法 transfer,参数,输出 等等 30 | Function function = new Function("transfer", inputParameters, outputParameters); 31 | //将合约数据转换成16进制字符串 32 | String dataStr = FunctionEncoder.encode(function); 33 | RawTransaction tx = RawTransaction.createTransaction( 34 | BigInteger.valueOf(Long.parseLong(nonce)), 35 | BigInteger.valueOf(gasPrice),//gasPrice 36 | BigInteger.valueOf(gasLimit),//gasLimit 37 | toAddress, 38 | BigInteger.valueOf(amount),//转账的"数量" 39 | ""); 40 | //创建钥匙对 41 | ECKeyPair ecKeyPair = ECKeyPair.create(Numeric.toBigInt(privateKey)); 42 | Credentials credentials = Credentials.create(ecKeyPair); 43 | System.out.println(credentials.getAddress()); 44 | //签名交易 45 | byte[] signed = TransactionEncoder.signMessage(tx, credentials); 46 | //将签名的交易转换成16进制字符串,并用于广播交易 47 | signedStr = Numeric.toHexString(signed); 48 | } catch (Exception e) { 49 | 50 | } 51 | return signedStr; 52 | } 53 | 54 | public String getAddress(String privateKey){ 55 | ECKeyPair ecKeyPair = ECKeyPair.create(Numeric.toBigInt(privateKey)); 56 | Credentials credentials = Credentials.create(ecKeyPair); 57 | return credentials.getAddress(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/utils/BTCWalletUtil.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.utils; 2 | 3 | 4 | import com.tokenview.bean.WalletBean; 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.bitcoinj.core.*; 7 | import org.bitcoinj.crypto.ChildNumber; 8 | import org.bitcoinj.crypto.DeterministicKey; 9 | import org.bitcoinj.crypto.HDKeyDerivation; 10 | import org.bitcoinj.params.MainNetParams; 11 | import org.bitcoinj.wallet.DeterministicSeed; 12 | import org.bouncycastle.util.encoders.Hex; 13 | import org.web3j.crypto.ECKeyPair; 14 | import org.web3j.utils.Numeric; 15 | 16 | import java.util.List; 17 | 18 | 19 | public class BTCWalletUtil { 20 | 21 | // public static boolean BTC_TEST_NET = SharedPreferencesUtil.getInstance().getBoolean(NumberConstant.IS_TEST_NET,false); 22 | public static String BTC_TEST_PATH = "m/44'/1'/0'/0/0"; 23 | public static String BTC_MAIN_PATH = "m/44'/0'/0'/0/0"; 24 | public static String BTC_SEGWIT_MAIN_PATH = "m/49'/0'/0'/0/0"; 25 | public static String BTC_SEGWIT_TEST_PATH = "m/49'/1'/0'/0/0"; 26 | public static String ETH_MAIN_PATH="m/44'/60'/0'/0/0"; 27 | 28 | /** 29 | * 通过助记词生成私钥 30 | */ 31 | public static WalletBean loadWalletByDeterministicSeed(DeterministicSeed ds, String pwd, String walletName) { 32 | String path; 33 | NetworkParameters params; 34 | path = BTC_MAIN_PATH; 35 | params = MainNetParams.get(); 36 | ECKeyPair keyPair = getEcKeyPairByDeterministicSeed(path, ds); 37 | // loadWalletBIP49ByDeterministicSeed(ds); 38 | if (keyPair == null) return null; 39 | // 获取Base64编码的64位的私钥 40 | // String privateKey = Numeric.toHexStringNoPrefixZeroPadded(keyPair.getPrivateKey(), Keys.PRIVATE_KEY_LENGTH_IN_HEX); 41 | // //第二种方式生成 42 | // ECKeyPair ecKeyPair = generateEcKeyPair(ds); 43 | ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey()); 44 | //获取Base58编码压缩后的私钥 45 | String privateKeyAsWiF = ecKey.getPrivateKeyAsWiF(params); 46 | String address = ecKey.toAddress(params).toString(); 47 | WalletBean bean = new WalletBean(); 48 | bean.setCoin_type("BTC"); 49 | bean.setMnemonic(getMnemonic(ds)); 50 | bean.setAddress(address); 51 | bean.setKeystore(""); 52 | bean.setPrivateKey(privateKeyAsWiF); 53 | return bean; 54 | } 55 | 56 | 57 | /** 58 | * 通过助记词生成 BIP49 协议的隔离见证地址 59 | */ 60 | public static WalletBean loadWalletBIP49ByDeterministicSeed(List mnemonic) { 61 | DeterministicSeed ds = getDeterministicSeed(mnemonic); 62 | String path=BTC_SEGWIT_MAIN_PATH; 63 | NetworkParameters params= MainNetParams.get(); 64 | String[] pathArray = path.split("/"); 65 | byte[] seedBytes = ds.getSeedBytes(); 66 | DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes); 67 | for (int i = 1; i < pathArray.length; i++) { 68 | ChildNumber childNumber; 69 | if (pathArray[i].endsWith("'")) { 70 | int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1)); 71 | childNumber = new ChildNumber(number, true); 72 | } else { 73 | int number = Integer.parseInt(pathArray[i]); 74 | childNumber = new ChildNumber(number, false); 75 | } 76 | dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber); 77 | } 78 | //获取P2SH地址的过程 79 | String publicKey=Numeric.toHexStringNoPrefix(dkKey.getPubKeyHash()); 80 | String redeemScript = String.format("0x0014%s", publicKey); 81 | byte[] bytes = Numeric.hexStringToByteArray(redeemScript); 82 | byte[] bytes1 = Utils.sha256hash160(bytes); 83 | String p2shAddress = Address.fromP2SHHash(params, bytes1).toBase58(); 84 | System.out.println("p2sh account == "+p2shAddress); 85 | WalletBean bean=new WalletBean(); 86 | bean.setCoin_type("BTC"); 87 | bean.setAddress(p2shAddress); 88 | bean.setMnemonic(getMnemonic(ds)); 89 | bean.setPrivateKey(dkKey.getPrivateKeyAsWiF(params)); 90 | return bean; 91 | } 92 | 93 | 94 | 95 | /** 96 | * 通过助记词生成hex私钥,WIF私钥,也可生成地址 97 | */ 98 | public static WalletBean loadWalletByDeterministicSeedTest(DeterministicSeed ds, String pwd, String walletName) { 99 | String path; 100 | NetworkParameters params; 101 | path = BTC_MAIN_PATH; 102 | params = MainNetParams.get(); 103 | //params = TestNet3Params.get(); 104 | ECKeyPair keyPair = getEcKeyPairByDeterministicSeed(path, ds); 105 | if (keyPair == null) return null; 106 | // 获取Base64编码的64位的私钥 107 | // String privateKey = Numeric.toHexStringNoPrefixZeroPadded(keyPair.getPrivateKey(), Keys.PRIVATE_KEY_LENGTH_IN_HEX); 108 | // 第二种方式生成 109 | // ECKeyPair ecKeyPair = generateEcKeyPair(ds); 110 | ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey()); 111 | String hexPrivateKey = ecKey.getPrivateKeyAsHex(); 112 | ECKey ecKey1 = ECKey.fromPrivate(Hex.decode(hexPrivateKey)); 113 | Address address1 = ecKey1.toAddress(params); 114 | System.out.println("bitcoin account == "+address1); 115 | //获取Base58编码压缩后的私钥 116 | System.out.println("privateKeyHex == "+ecKey.getPrivateKeyAsHex()); 117 | //ecKey. 118 | String privateKeyAsWiF = ecKey.getPrivateKeyAsWiF(params); 119 | System.out.println("privateKeyWif =="+privateKeyAsWiF); 120 | String address = ecKey.toAddress(params).toString(); 121 | System.out.println("bitcoin account == "+address); 122 | WalletBean bean = new WalletBean(); 123 | bean.setCoin_type("BTC"); 124 | bean.setMnemonic(getMnemonic(ds)); 125 | bean.setAddress(address); 126 | bean.setKeystore(""); 127 | bean.setPrivateKey(privateKeyAsWiF); 128 | return bean; 129 | } 130 | 131 | /** 132 | * 通过私钥导入BTC钱包 (base58) 133 | * */ 134 | public static WalletBean loadWalletByPrivateKey(String privateKey) { 135 | NetworkParameters params; 136 | params = MainNetParams.get(); 137 | try { 138 | DumpedPrivateKey priKey = DumpedPrivateKey.fromBase58(params, privateKey); 139 | ECKey ecKey = priKey.getKey(); 140 | String address = ecKey.toAddress(params).toString(); 141 | WalletBean bean = new WalletBean(); 142 | bean.setCoin_type("BTC"); 143 | bean.setMnemonic(" "); 144 | bean.setAddress(address); 145 | bean.setKeystore(""); 146 | bean.setPrivateKey(privateKey); 147 | return bean; 148 | }catch (Exception e){ 149 | e.printStackTrace(); 150 | } 151 | return null; 152 | } 153 | 154 | 155 | /** 156 | * 通过助记词生成私钥 157 | */ 158 | public static WalletBean loadWalletByMnemonic(String currency,List list, String pwd, String walletName) { 159 | String path; 160 | NetworkParameters params; 161 | path = ""; 162 | if (currency.equalsIgnoreCase("btc")) { 163 | path = BTC_MAIN_PATH; 164 | } 165 | if (currency.equalsIgnoreCase("eth")) { 166 | path = ETH_MAIN_PATH; 167 | } 168 | params = MainNetParams.get(); 169 | DeterministicSeed ds = getDeterministicSeed(list); 170 | ECKeyPair keyPair = getEcKeyPairByDeterministicSeed(path, ds); 171 | // //获取16编码的64位的私钥 172 | // String privateKey = Numeric.toHexStringNoPrefixZeroPadded(keyPair.getPrivateKey(), Keys.PRIVATE_KEY_LENGTH_IN_HEX); 173 | // ECKeyPair ecKeyPair = generateEcKeyPair(ds); 174 | ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey()); 175 | //获取Base58编码压缩后的私钥 176 | String privateKeyAsWiF = ecKey.getPrivateKeyAsWiF(params); 177 | String address = ecKey.toAddress(params).toString(); 178 | System.out.println("privateKey ===="+ecKey.getPrivateKeyAsHex()); 179 | System.out.println("account ====="+address); 180 | WalletBean bean = new WalletBean(); 181 | bean.setCoin_type("BTC"); 182 | bean.setMnemonic(getMnemonic(ds)); 183 | bean.setAddress(address); 184 | bean.setKeystore(""); 185 | bean.setPrivateKey(privateKeyAsWiF); 186 | return bean; 187 | } 188 | 189 | 190 | /** 191 | * 通过路径和种子获取私钥对 192 | */ 193 | public static ECKeyPair getEcKeyPairByDeterministicSeed(String path, DeterministicSeed ds) { 194 | String[] pathArray = path.split("/"); 195 | byte[] seedBytes = ds.getSeedBytes(); 196 | if (seedBytes == null) 197 | return null; 198 | DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes); 199 | for (int i = 1; i < pathArray.length; i++) { 200 | ChildNumber childNumber; 201 | if (pathArray[i].endsWith("'")) { 202 | int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1)); 203 | childNumber = new ChildNumber(number, true); 204 | } else { 205 | int number = Integer.parseInt(pathArray[i]); 206 | childNumber = new ChildNumber(number, false); 207 | } 208 | dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber); 209 | } 210 | ECKeyPair keyPair = ECKeyPair.create(dkKey.getPrivKeyBytes()); 211 | return keyPair; 212 | } 213 | 214 | 215 | 216 | /** 217 | * 通过路径和种子获取私钥对 218 | */ 219 | public static DeterministicKey getPrivateBySeed(String path, DeterministicSeed ds) { 220 | String[] pathArray = path.split("/"); 221 | byte[] seedBytes = ds.getSeedBytes(); 222 | if (seedBytes == null) 223 | return null; 224 | DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes); 225 | for (int i = 1; i < pathArray.length; i++) { 226 | ChildNumber childNumber; 227 | if (pathArray[i].endsWith("'")) { 228 | int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1)); 229 | childNumber = new ChildNumber(number, true); 230 | } else { 231 | int number = Integer.parseInt(pathArray[i]); 232 | childNumber = new ChildNumber(number, false); 233 | } 234 | dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber); 235 | } 236 | // ECKeyPair keyPair = ECKeyPair.create(dkKey.getPrivKeyBytes()); 237 | return dkKey; 238 | } 239 | 240 | 241 | 242 | /** 243 | * 通过助记词生成种子 244 | * */ 245 | public static DeterministicSeed getDeterministicSeed(List list) { 246 | try { 247 | long creationTimeSeconds = System.currentTimeMillis() / 1000; 248 | return new DeterministicSeed(list, null, "", creationTimeSeconds); 249 | }catch (Exception e){} 250 | return null; 251 | } 252 | 253 | /** 254 | * 通过助记词生成Hex私钥 255 | * */ 256 | public static String getPrivateKeyHex(List list) { 257 | try { 258 | long creationTimeSeconds = System.currentTimeMillis() / 1000; 259 | DeterministicSeed seed = new DeterministicSeed(list, null, "", creationTimeSeconds); 260 | ECKeyPair keyPair = getEcKeyPairByDeterministicSeed("m/44'/1'/0'/0/0", seed); 261 | if (keyPair == null) return null; 262 | ECKey ecKey = ECKey.fromPrivate(keyPair.getPrivateKey()); 263 | String hexPrivateKey = ecKey.getPrivateKeyAsHex(); 264 | return hexPrivateKey; 265 | }catch (Exception e){} 266 | return null; 267 | } 268 | 269 | /** 270 | * 通过种子生成助记词字符串 271 | */ 272 | public static String getMnemonic(DeterministicSeed ds) { 273 | StringBuilder sb = new StringBuilder(); 274 | List mnemonicList = ds.getMnemonicCode(); 275 | for (int i = 0; mnemonicList != null && i < mnemonicList.size(); i++) { 276 | sb.append(mnemonicList.get(i) + " "); 277 | } 278 | return sb.toString().trim(); 279 | } 280 | 281 | /**判断地址的有效性*/ 282 | public static boolean isBTCValidAddress(String input) { 283 | if (StringUtils.isEmpty(input))return false; 284 | try { 285 | NetworkParameters networkParameters = null; 286 | networkParameters = MainNetParams.get(); 287 | Address address = Address.fromBase58(networkParameters, input); 288 | if (address != null) 289 | return true; 290 | else 291 | return false; 292 | } catch (Exception e) { 293 | return false; 294 | } 295 | } 296 | 297 | 298 | } 299 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/utils/ECKeyUtil.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.utils; 2 | 3 | import com.tokenview.enums.Coin; 4 | import org.bitcoinj.crypto.ChildNumber; 5 | import org.bitcoinj.crypto.DeterministicKey; 6 | import org.bitcoinj.crypto.HDKeyDerivation; 7 | import org.bitcoinj.wallet.DeterministicSeed; 8 | import org.bitcoinj.wallet.UnreadableWalletException; 9 | import org.web3j.crypto.ECKeyPair; 10 | 11 | public class ECKeyUtil { 12 | 13 | 14 | public static ECKeyPair generateEcKey(String mnemonic, Coin coin) throws UnreadableWalletException { 15 | DeterministicSeed seed = getDeterministicSeed(mnemonic); 16 | return getEcKeyPairByDeterministicSeed(coin.getPath(),seed); 17 | } 18 | 19 | private static DeterministicSeed getDeterministicSeed(String mnemonic) throws UnreadableWalletException { 20 | long creationTimeSeconds = System.currentTimeMillis() / 1000; 21 | return new DeterministicSeed(mnemonic, null, "", creationTimeSeconds); 22 | } 23 | 24 | private static ECKeyPair getEcKeyPairByDeterministicSeed(String path, DeterministicSeed ds) { 25 | String [] pathArray = path.split("/"); 26 | byte[] seedBytes = ds.getSeedBytes(); 27 | if (seedBytes == null) 28 | return null; 29 | DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes); 30 | ChildNumber childNumber; 31 | for (int i = 1; i < pathArray.length; i++) { 32 | if (pathArray[i].endsWith("'")) { 33 | int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1)); 34 | childNumber = new ChildNumber(number, true); 35 | } else { 36 | int number = Integer.parseInt(pathArray[i]); 37 | childNumber = new ChildNumber(number, false); 38 | } 39 | dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber); 40 | } 41 | return ECKeyPair.create(dkKey.getPrivKeyBytes()); 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/utils/HexUtil.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.utils; 2 | 3 | /** 4 | * @author zhaoda 5 | * @date 2020/6/1. 6 | * GitHub: 7 | * email: 8 | * description: 9 | */ 10 | public class HexUtil { 11 | private static final char[] digits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 12 | public static final byte[] emptybytes = new byte[0]; 13 | 14 | public HexUtil() { 15 | } 16 | 17 | public static String byte2HexStr(byte b) { 18 | char[] buf = new char[]{'\u0000', digits[b & 15]}; 19 | b = (byte)(b >>> 4); 20 | buf[0] = digits[b & 15]; 21 | return new String(buf); 22 | } 23 | 24 | public static String bytes2HexStr(byte[] bytes) { 25 | if (bytes != null && bytes.length != 0) { 26 | char[] buf = new char[2 * bytes.length]; 27 | 28 | for(int i = 0; i < bytes.length; ++i) { 29 | byte b = bytes[i]; 30 | buf[2 * i + 1] = digits[b & 15]; 31 | b = (byte)(b >>> 4); 32 | buf[2 * i + 0] = digits[b & 15]; 33 | } 34 | 35 | return new String(buf); 36 | } else { 37 | return null; 38 | } 39 | } 40 | 41 | public static byte hexStr2Byte(String str) { 42 | return str != null && str.length() == 1 ? char2Byte(str.charAt(0)) : 0; 43 | } 44 | 45 | public static byte char2Byte(char ch) { 46 | if (ch >= '0' && ch <= '9') { 47 | return (byte)(ch - 48); 48 | } else if (ch >= 'a' && ch <= 'f') { 49 | return (byte)(ch - 97 + 10); 50 | } else { 51 | return ch >= 'A' && ch <= 'F' ? (byte)(ch - 65 + 10) : 0; 52 | } 53 | } 54 | 55 | public static byte[] hexStr2Bytes(String str) { 56 | if (str != null && !str.equals("")) { 57 | byte[] bytes = new byte[str.length() / 2]; 58 | 59 | for(int i = 0; i < bytes.length; ++i) { 60 | char high = str.charAt(i * 2); 61 | char low = str.charAt(i * 2 + 1); 62 | bytes[i] = (byte)(char2Byte(high) * 16 + char2Byte(low)); 63 | } 64 | 65 | return bytes; 66 | } else { 67 | return emptybytes; 68 | } 69 | } 70 | 71 | public static void main(String[] args) { 72 | try { 73 | byte[] bytes = "Hello WebSocket World?".getBytes("gbk"); 74 | System.out.println(bytes2HexStr(bytes)); 75 | } catch (Exception var3) { 76 | var3.printStackTrace(); 77 | } 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/utils/HttpClientUtils.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.utils; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.google.common.collect.Lists; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.apache.http.HttpEntity; 9 | import org.apache.http.NameValuePair; 10 | import org.apache.http.client.config.RequestConfig; 11 | import org.apache.http.client.entity.UrlEncodedFormEntity; 12 | import org.apache.http.client.methods.*; 13 | import org.apache.http.client.utils.URIBuilder; 14 | import org.apache.http.config.Registry; 15 | import org.apache.http.config.RegistryBuilder; 16 | import org.apache.http.conn.socket.ConnectionSocketFactory; 17 | import org.apache.http.conn.socket.PlainConnectionSocketFactory; 18 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 19 | import org.apache.http.entity.ContentType; 20 | import org.apache.http.entity.StringEntity; 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.impl.client.HttpClients; 23 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 24 | import org.apache.http.message.BasicNameValuePair; 25 | import org.apache.http.util.EntityUtils; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import javax.net.ssl.*; 30 | import java.io.BufferedReader; 31 | import java.io.IOException; 32 | import java.io.InputStream; 33 | import java.io.InputStreamReader; 34 | import java.net.URISyntaxException; 35 | import java.nio.charset.Charset; 36 | import java.security.KeyManagementException; 37 | import java.security.NoSuchAlgorithmException; 38 | import java.security.cert.CertificateException; 39 | import java.util.*; 40 | 41 | @Deprecated 42 | @Slf4j 43 | public final class HttpClientUtils { 44 | 45 | private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class); 46 | 47 | public static String get(final String url, final Map params, final Map headerMap) { 48 | HttpGet httpGet = null; 49 | try { 50 | URIBuilder ub = new URIBuilder(url); 51 | List pairs = Lists.newArrayList(); 52 | 53 | if (params != null && !params.isEmpty()) { 54 | for (Map.Entry entry : params.entrySet()) { 55 | pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString())); 56 | } 57 | 58 | ub.setParameters(pairs); 59 | } 60 | httpGet = new HttpGet(ub.build()); 61 | } catch (URISyntaxException e) { 62 | e.printStackTrace(); 63 | } 64 | return execute(httpGet, headerMap); 65 | } 66 | 67 | public static String get(final String url, final Map headerMap) { 68 | return get(url, null, headerMap); 69 | } 70 | 71 | public static JSONObject getReturnObject(final String url, final Map headerMap) { 72 | String str = get(url, null, headerMap); 73 | JSONObject json = null; 74 | try { 75 | json = JSONObject.parseObject(str); 76 | } catch (Exception e) { 77 | log.info("this resquest return not json object" + str); 78 | json = new JSONObject(); 79 | } 80 | 81 | return json; 82 | } 83 | 84 | public static JSONArray getReturnArray(final String url, final Map headerMap) { 85 | String str = get(url, null, headerMap); 86 | JSONArray json = null; 87 | try { 88 | json = JSONArray.parseArray(str); 89 | } catch (Exception e) { 90 | log.info("this resquest return not json array" + str); 91 | json = new JSONArray(); 92 | } 93 | 94 | return json; 95 | } 96 | 97 | public static String post(final String url, final Map params, 98 | final Map headerMap) { 99 | return post(url, params, headerMap, "utf-8"); 100 | } 101 | 102 | public static String post(final String url, final Map params) { 103 | return post(url, params, null, "utf-8"); 104 | } 105 | 106 | public static String post(final String url, final Map params, final Map headerMap, 107 | final String charset) { 108 | final HttpPost request = new HttpPost(url); 109 | if (params != null && params.size() > 0) { 110 | List paramList = null; 111 | final Set> entrySet = params.entrySet(); 112 | paramList = new ArrayList<>(); 113 | for (final Iterator> it = entrySet.iterator(); it.hasNext(); ) { 114 | final Map.Entry entry = it.next(); 115 | final String key = entry.getKey(); 116 | final Object value = entry.getValue(); 117 | if (key != null && value != null) { 118 | final NameValuePair nvp = new BasicNameValuePair(key, value.toString()); 119 | paramList.add(nvp); 120 | } 121 | } 122 | try { 123 | if (StringUtils.isEmpty(charset)) { 124 | request.setEntity(new UrlEncodedFormEntity(paramList)); 125 | } else { 126 | request.setEntity(new UrlEncodedFormEntity(paramList, Charset.forName(charset))); 127 | } 128 | } catch (final Exception e) { 129 | logger.error("HttpClientUtils post", e); 130 | return null; 131 | } 132 | } 133 | return execute(request, headerMap); 134 | } 135 | 136 | public static String post(final String url, final HttpEntity entity, final Map headerMap) { 137 | final HttpPost request = new HttpPost(url); 138 | request.setEntity(entity); 139 | return execute(request, headerMap); 140 | } 141 | 142 | public static String execute(final HttpRequestBase request, final Map headerMap) { 143 | return execute(null, request, headerMap); 144 | } 145 | 146 | public static String execute(CloseableHttpClient httpclient, final HttpRequestBase request, 147 | final Map headerMap) { 148 | return execute(null, request, headerMap, 30000, 30000); 149 | } 150 | 151 | public static String execute(final HttpRequestBase request, 152 | final Map headerMap, int socketTimeout, int connectTimeout) { 153 | return execute(null, request, headerMap, socketTimeout, connectTimeout); 154 | } 155 | 156 | private static String execute(CloseableHttpClient httpclient, final HttpRequestBase request, 157 | final Map headerMap, int socketTimeout, int connectTimeout) { 158 | final StringBuffer log = new StringBuffer( 159 | "HttpClientUtils execute method:" + request.getMethod() + " url:" + request.getURI()); 160 | 161 | boolean isClose = false; 162 | if (httpclient == null) { 163 | httpclient = HttpClients.createDefault(); 164 | isClose = true; 165 | } 166 | InputStream resStream = null; 167 | InputStreamReader inputStreamReader = null; 168 | BufferedReader br = null; 169 | String result = ""; 170 | 171 | if (headerMap != null && headerMap.size() > 0) { 172 | final Iterator iterator = headerMap.keySet().iterator(); 173 | while (iterator.hasNext()) { 174 | final String key = iterator.next(); 175 | request.setHeader(key, headerMap.get(key)); 176 | } 177 | } 178 | 179 | try { 180 | final RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout( 181 | connectTimeout) 182 | .build(); 183 | request.setConfig(requestConfig); 184 | final CloseableHttpResponse response = httpclient.execute(request); 185 | 186 | try { 187 | 188 | final HttpEntity entity = response.getEntity(); 189 | 190 | if (entity != null) { 191 | resStream = entity.getContent(); 192 | try { 193 | inputStreamReader = new InputStreamReader(resStream); 194 | br = new BufferedReader(inputStreamReader); 195 | final StringBuffer resBuffer = new StringBuffer(); 196 | String resTemp = ""; 197 | while ((resTemp = br.readLine()) != null) { 198 | resBuffer.append(resTemp); 199 | } 200 | result = resBuffer.toString(); 201 | } finally { 202 | if (br != null) { 203 | br.close(); 204 | } 205 | if (inputStreamReader != null) { 206 | inputStreamReader.close(); 207 | } 208 | if (resStream != null) { 209 | resStream.close(); 210 | } 211 | } 212 | } 213 | } finally { 214 | response.close(); 215 | } 216 | } catch (final Exception e) { 217 | request.abort(); 218 | logger.error(log.toString(), e); 219 | } finally { 220 | request.abort(); 221 | try { 222 | if (isClose) { 223 | httpclient.close(); 224 | } 225 | } catch (final IOException e) { 226 | logger.error(log.toString(), e); 227 | } 228 | } 229 | return result; 230 | } 231 | 232 | public static JSONObject post(String url, JSONObject params, Map header) { 233 | try { 234 | 235 | //创建post方式请求对象 236 | HttpPost httpPost = new HttpPost(url); 237 | if (header != null) { 238 | for (Map.Entry entry : header.entrySet()) { 239 | httpPost.setHeader(entry.getKey(), entry.getValue()); 240 | } 241 | } else { 242 | //设置header信息 243 | httpPost.setHeader("Content-type", "application/json;charset=utf-8"); 244 | httpPost.setHeader("Accept", "application/json;charset=utf-8"); 245 | } 246 | 247 | // 248 | StringEntity requestEntity = new StringEntity( 249 | params.toJSONString(), 250 | ContentType.APPLICATION_JSON); 251 | httpPost.setEntity(requestEntity); 252 | 253 | log.debug("请求地址:" + url); 254 | log.debug("请求参数:" + params.toJSONString()); 255 | 256 | return JSONObject.parseObject(send(httpPost, "UTF-8")); 257 | } catch (Exception e) { 258 | e.printStackTrace(); 259 | } 260 | 261 | return null; 262 | } 263 | 264 | public static String httpsGet(String url, Map header) { 265 | try { 266 | //创建post方式请求对象 267 | HttpGet httpGet = new HttpGet(url); 268 | 269 | if (header != null) { 270 | for (Map.Entry entry : header.entrySet()) { 271 | httpGet.setHeader(entry.getKey(), entry.getValue()); 272 | } 273 | } 274 | 275 | //设置header信息 276 | httpGet.setHeader("Content-type", "application/json;charset=utf-8"); 277 | httpGet.setHeader("Accept", "application/json;charset=utf-8"); 278 | 279 | log.debug("请求地址:" + url); 280 | 281 | return send(httpGet, "UTF-8"); 282 | } catch (Exception e) { 283 | e.printStackTrace(); 284 | } 285 | 286 | return null; 287 | } 288 | 289 | private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException { 290 | SSLContext sc = SSLContext.getInstance("TLSv1.2"); 291 | 292 | // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 293 | X509TrustManager trustManager = new X509TrustManager() { 294 | @Override 295 | public void checkClientTrusted( 296 | java.security.cert.X509Certificate[] paramArrayOfX509Certificate, 297 | String paramString) throws CertificateException { 298 | } 299 | 300 | @Override 301 | public void checkServerTrusted( 302 | java.security.cert.X509Certificate[] paramArrayOfX509Certificate, 303 | String paramString) throws CertificateException { 304 | } 305 | 306 | @Override 307 | public java.security.cert.X509Certificate[] getAcceptedIssuers() { 308 | return null; 309 | } 310 | }; 311 | 312 | sc.init(null, new TrustManager[] {trustManager}, null); 313 | return sc; 314 | } 315 | 316 | public static String send(HttpRequestBase requestBase, String encoding) 317 | throws KeyManagementException, NoSuchAlgorithmException, IOException { 318 | String body = ""; 319 | //采用绕过验证的方式处理https请求 320 | SSLContext sslcontext = createIgnoreVerifySSL(); 321 | 322 | // 设置协议http和https对应的处理socket链接工厂的对象 323 | Registry socketFactoryRegistry = RegistryBuilder.create() 324 | .register("http", PlainConnectionSocketFactory.INSTANCE) 325 | .register("https", new SSLConnectionSocketFactory(sslcontext)) 326 | .build(); 327 | PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); 328 | HttpClients.custom().setConnectionManager(connManager); 329 | 330 | //创建自定义的httpclient对象 331 | CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).setSSLHostnameVerifier( 332 | new TrustAnyHostnameVerifier()).build(); 333 | 334 | //CloseableHttpClient client = HttpClients.createDefault(); 335 | 336 | //执行请求操作,并拿到结果(同步阻塞) 337 | CloseableHttpResponse response = client.execute(requestBase); 338 | //获取结果实体 339 | HttpEntity entity = response.getEntity(); 340 | if (entity != null) { 341 | //按指定编码转换结果实体为String类型 342 | body = EntityUtils.toString(entity, encoding); 343 | } 344 | EntityUtils.consume(entity); 345 | //释放链接 346 | response.close(); 347 | client.close(); 348 | connManager.close(); 349 | return body; 350 | } 351 | 352 | private static class TrustAnyHostnameVerifier implements HostnameVerifier { 353 | @Override 354 | public boolean verify(String hostname, SSLSession session) { 355 | return true; 356 | } 357 | } 358 | 359 | public static String put(final String url, final HttpEntity entity, final Map headerMap) { 360 | final HttpPut request = new HttpPut(url); 361 | request.setEntity(entity); 362 | return execute(request, headerMap); 363 | } 364 | 365 | public static String put(final String url, final Map headerMap) { 366 | final HttpPut request = new HttpPut(url); 367 | return execute(request, headerMap); 368 | } 369 | 370 | } 371 | -------------------------------------------------------------------------------- /sign-java-sdk/src/main/java/com/tokenview/utils/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.utils; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.alibaba.fastjson.JSONObject; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.util.HashMap; 9 | import java.util.List; 10 | 11 | @Slf4j 12 | public class HttpUtil { 13 | 14 | private String get(String url) { 15 | return HttpClientUtils.get(url, new HashMap<>()); 16 | } 17 | 18 | public JSONObject getTransactionDetail(String tx){ 19 | StringBuffer url = new StringBuffer("https://chain.api.btc.com/v3/tx/"); 20 | url.append(tx); 21 | url.append("?verbose=3"); 22 | String result = null; 23 | try { 24 | result = get(url.toString()); 25 | } catch (Exception e) { 26 | log.info(e.getMessage(), e); 27 | } 28 | return JSONObject.parseObject(result); 29 | } 30 | 31 | public JSONArray getUnspent(String txid,List addrList){ 32 | JSONObject result =new HttpUtil().getTransactionDetail(txid).getJSONObject("data"); 33 | long height =result.getLong("block_height"); 34 | JSONArray outputsArray = result.getJSONArray("outputs"); 35 | JSONArray unspents = new JSONArray(); 36 | int index =0; 37 | for (Object o : outputsArray){ 38 | Object io = JSONObject.parseObject(o.toString()).get("addresses"); 39 | String address = String.valueOf(io).replace("[\"","").replace("\"]",""); 40 | if (addrList.contains(address)){ 41 | JSONObject txJson = JSONObject.parseObject(o.toString()); 42 | txJson.put("txid",txid); 43 | txJson.put("tx_output_n",index); 44 | txJson.put("block_height",height); 45 | unspents.add(txJson); 46 | } 47 | index++; 48 | } 49 | log.info(JSON.toJSONString(unspents)); 50 | return unspents; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /sign-java-sdk/src/test/java/com/tokenview/sign/test/BTCSignTest.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.sign.test; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.tokenview.sign.btc.BTCSign; 7 | import com.tokenview.utils.HttpUtil; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.junit.Test; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | @Slf4j 15 | public class BTCSignTest { 16 | 17 | @Test 18 | public void testGetUnspent(){ 19 | String txid = "13c6235ee5e6403606f1539bc872813ac14a90521da6248ffbf63913a8675573"; 20 | List addrList = new ArrayList<>(); 21 | addrList.add("1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ"); 22 | JSONArray unspents =new HttpUtil().getUnspent(txid,addrList); 23 | log.info(JSON.toJSONString(unspents)); 24 | } 25 | 26 | 27 | @Test 28 | public void testBTCSign(){ 29 | //unspent所在txid和所在地址 30 | String txid = "6680c65d3b1f4ab61b7096441a257de51f8bab48d0dca2f76080891ad9b0796a"; 31 | List addrList = new ArrayList<>(); 32 | addrList.add("1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ"); 33 | //可自行设置多个输出地址和金额,找零地址和金额 34 | JSONArray unspents =new HttpUtil().getUnspent(txid,addrList); 35 | long inputAmount =unspents 36 | .stream() 37 | .mapToLong(o->JSONObject.parseObject(o.toString()).getLong("value")) 38 | .sum(); 39 | 40 | JSONArray outputs = new JSONArray(); 41 | JSONObject outputTo = new JSONObject(); 42 | outputTo.put("account","16SzvWdCrYsVsMuRp43TfqvGvibBah7s17"); 43 | outputTo.put("amount",10000); 44 | outputs.add(outputTo); 45 | long outputToAmount = outputs 46 | .stream() 47 | .mapToLong(o -> JSONObject.parseObject(o.toString()).getLong("amount")) 48 | .sum(); 49 | long outputChangeAmount = inputAmount - outputToAmount; 50 | //input金额不足输出和找零返回不签名 51 | if (outputChangeAmount<=0){ 52 | return; 53 | } 54 | JSONObject outputChange = new JSONObject(); 55 | outputChange.put("account","1LEHMmGUAzjvMFCoaoUsY46avHzCN3pUdQ"); 56 | outputChange.put("amount",outputChangeAmount); 57 | 58 | outputs.add(outputChange); 59 | 60 | //找零金额小于等于手续费返回不签名 61 | long fee = (unspents.size() + outputs.size() * 2) * 148 - 10; 62 | if (outputChangeAmount <= fee) { 63 | return; 64 | } 65 | 66 | String signature = new BTCSign().signBTCTransaction("L2xigpefbyesCnzR5hJDFxKPD4A2qSuNHiz4utWnqEovhownw8U2",unspents,outputs); 67 | log.info(signature); 68 | } 69 | 70 | @Test 71 | public void testGetAddress(){ 72 | log.info(new BTCSign().getAddress("d71405cd1c95271e4c17569494100856d9e8706e081702ec5ec91a5b20ce1957")); 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sign-java-sdk/src/test/java/com/tokenview/sign/test/ETHSignTest.java: -------------------------------------------------------------------------------- 1 | package com.tokenview.sign.test; 2 | 3 | import com.tokenview.sign.eth.ETHSign; 4 | import com.tokenview.utils.BTCWalletUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.Test; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Slf4j 12 | public class ETHSignTest { 13 | 14 | @Test 15 | public void testGetPrivateKeyFromStrList() { 16 | List stringList = new ArrayList(); 17 | stringList.add("gym"); 18 | stringList.add("please"); 19 | stringList.add("sauce"); 20 | stringList.add("elephant"); 21 | stringList.add("trap"); 22 | stringList.add("bag"); 23 | stringList.add("logic"); 24 | stringList.add("okay"); 25 | stringList.add("impulse"); 26 | stringList.add("slogan"); 27 | stringList.add("goose"); 28 | stringList.add("birth"); 29 | BTCWalletUtil.loadWalletByMnemonic("eth",stringList,",",""); 30 | } 31 | 32 | @Test 33 | public void testGetAddress() { 34 | String address = new ETHSign().getAddress("b71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f"); 35 | log.info(address); 36 | } 37 | 38 | @Test 39 | public void testETHSign() { 40 | 41 | String sinature = new ETHSign().signETHTransaction( 42 | "0xb71a7616b42110d8345ddc6826ec42c2f1ce24d5f4d8efeb616168d5c1ef4a1f", 43 | "0x9Ae75431335d2e70f8DB0b35F6C179a43756f78e", 44 | "1", 45 | 78500000000L, 46 | 21000L, 47 | 80000000000L); 48 | log.info(sinature); 49 | } 50 | 51 | } 52 | --------------------------------------------------------------------------------