diff --git a/README.md b/README.md index 4d4c998..126ee82 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,10 @@ -# web3j-sample -web3 for java 样例程序 (基于web3j 3.4.0) -环境 idea maven -运行前提 需要有一个开启RPC或者IPC服务的以太坊节点 +# web3j LinkToken Support -- [QuickStart](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/QuickStart.java) 快速开始 +- 扩展web3j功能使其支持LinkToken(WKC) -- [AccountManager](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/AccountManager.java) 账号相关接口 -- [TransactionClient](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/TransactionClient.java) eth转账相关接口 -- [TokenClient](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/TokenClient.java) token代币相关查询及转账 -- [ColdWallet](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/ColdWallet.java) 冷钱包创建、交易 -- [TokenBalanceTask](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/TokenBalanceTask.java) 批量token代币余额查询 -- [EthInfo](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/EthInfo.java) 连接节点的相关信息接口 -- [Security](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/Security.java) 公钥私钥相关接口 -- [EthMnemonic](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/EthMnemonic.java) 生成、导入助记词(需要比特币的jar包 可以查看pom.xml) -- [Filter](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/Filter.java) 新块、新交易相关监听 -- [ContractEvent](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/ContractEvent.java) 执行合约相关log监听 -- [DecodeMessage](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/DecodeMessage.java) 加密后的交易数据解析 -- [IBAN](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/IBAN.java) 根据官方规则生成iban及付款二维码 -- [Calculate](https://github.com/ethjava/web3j-sample/blob/master/src/main/java/com/ethjava/Calculate.java) 在发布合约前计算合约地址,根据签名后的交易信息计算TxHash +- LinkToken只能调用官方节点 并不开放所有接口 -基本功能demo已完成 +- 转账需要科学上网 -打赏 eth地址:0x248F272180db4D079443753336c5C847A080275c \ No newline at end of file +--- +打赏 WKC地址:0x248F272180db4D079443753336c5C847A080275c \ No newline at end of file diff --git a/src/main/java/com/ethjava/LinkToken/JsonRpcLinkWeb3j.java b/src/main/java/com/ethjava/LinkToken/JsonRpcLinkWeb3j.java new file mode 100644 index 0000000..9902510 --- /dev/null +++ b/src/main/java/com/ethjava/LinkToken/JsonRpcLinkWeb3j.java @@ -0,0 +1,23 @@ +package com.ethjava.LinkToken; + +import org.web3j.protocol.Web3jService; +import org.web3j.protocol.core.JsonRpc2_0Web3j; +import org.web3j.protocol.core.Request; + +import java.util.Arrays; + +public class JsonRpcLinkWeb3j extends JsonRpc2_0Web3j implements LinkToken { + public JsonRpcLinkWeb3j(Web3jService web3jService) { + super(web3jService); + } + + @Override + public Request linkTransactionRecord(String address, int page, int count) { + return new Request<>( + "getTransactionRecords", + Arrays.asList(address, "0", "0", String.valueOf(page), String.valueOf(count)), + web3jService, + LinkTransactionRecord.class); + } + +} diff --git a/src/main/java/com/ethjava/LinkToken/LInkTest.java b/src/main/java/com/ethjava/LinkToken/LInkTest.java new file mode 100644 index 0000000..86d6482 --- /dev/null +++ b/src/main/java/com/ethjava/LinkToken/LInkTest.java @@ -0,0 +1,44 @@ +package com.ethjava.LinkToken; + +import org.web3j.protocol.core.DefaultBlockParameterName; +import org.web3j.protocol.core.methods.response.*; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +public class LInkTest { + + public static String LINK_URL_TEST = "https://sandbox-walletapi.onethingpcs.com/"; + public static String LINK_URL_MAIN = "https://walletapi.onethingpcs.com/"; + + public static void main(String[] args) { + + JsonRpcLinkWeb3j linkWeb3j = new JsonRpcLinkWeb3j(new LinkHttpService(LINK_URL_TEST)); +// JsonRpcLinkWeb3j linkWeb3j = new JsonRpcLinkWeb3j(new LinkHttpService(LINK_URL_MAIN)); + + String address = "0x6c0f49af552f2326dd851b68832730cb7b6c0daf"; + + BigInteger balance = null; + + try { + EthGetBalance ethGetBalance = linkWeb3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send(); + balance = ethGetBalance.getBalance(); + System.out.println("address " + address + " balance " + balance + " wei"); + + EthGetTransactionCount ethGetTransactionCount = linkWeb3j.ethGetTransactionCount(address, DefaultBlockParameterName.PENDING).send(); + BigInteger nonce = ethGetTransactionCount.getTransactionCount(); + System.out.println("address " + address + " nonce " + nonce); + + LinkTransactionRecord linkTransactionRecord = linkWeb3j.linkTransactionRecord(address, 1, 40).send(); + List transactionRecord = linkTransactionRecord.getTransactionRecord(); + System.out.println("address " + address + " record " + Arrays.toString(transactionRecord.toArray())); + + } catch (IOException e) { + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/com/ethjava/LinkToken/LinkHttpService.java b/src/main/java/com/ethjava/LinkToken/LinkHttpService.java new file mode 100644 index 0000000..593e7ba --- /dev/null +++ b/src/main/java/com/ethjava/LinkToken/LinkHttpService.java @@ -0,0 +1,176 @@ +package com.ethjava.LinkToken; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import okhttp3.*; +import okhttp3.logging.HttpLoggingInterceptor; +import okio.Buffer; +import okio.BufferedSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.protocol.Service; +import org.web3j.protocol.exceptions.ClientConnectionException; +import org.web3j.protocol.http.HttpService; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +public class LinkHttpService extends Service { + + public static final MediaType JSON_MEDIA_TYPE + = MediaType.parse("application/json; charset=utf-8"); + + public static final String DEFAULT_URL = "http://localhost:8545/"; + + private static final Logger log = LoggerFactory.getLogger(HttpService.class); + + private OkHttpClient httpClient; + + private final String url; + + private final boolean includeRawResponse; + + private HashMap headers = new HashMap<>(); + + private HashMap linkRawTransactionHeads = new HashMap() { + { + put("Nc", "IN"); + } + }; + + + public LinkHttpService(String url, OkHttpClient httpClient, boolean includeRawResponses) { + super(includeRawResponses); + this.url = url; + this.httpClient = httpClient; + this.includeRawResponse = includeRawResponses; + } + + public LinkHttpService(OkHttpClient httpClient, boolean includeRawResponses) { + this(DEFAULT_URL, httpClient, includeRawResponses); + } + + private LinkHttpService(String url, OkHttpClient httpClient) { + this(url, httpClient, false); + } + + public LinkHttpService(String url) { + this(url, createOkHttpClient()); + } + + public LinkHttpService(String url, boolean includeRawResponse) { + this(url, createOkHttpClient(), includeRawResponse); + } + + public LinkHttpService(OkHttpClient httpClient) { + this(DEFAULT_URL, httpClient); + } + + public LinkHttpService(boolean includeRawResponse) { + this(DEFAULT_URL, includeRawResponse); + } + + public LinkHttpService() { + this(DEFAULT_URL); + } + + private static OkHttpClient createOkHttpClient() { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + configureLogging(builder); + return builder.build(); + } + + private static void configureLogging(OkHttpClient.Builder builder) { + if (log.isDebugEnabled()) { + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(log::debug); + logging.setLevel(HttpLoggingInterceptor.Level.BODY); + builder.addInterceptor(logging); + } + } + + @Override + protected InputStream performIO(String request) throws IOException { + /* headers */ + Headers headers = buildHeaders(); + /* body */ + JSONObject jsonObject = JSON.parseObject(request); + String method = jsonObject.getString("method"); + if (method.equals("getTransactionRecords")) { + JSONArray params = jsonObject.getJSONArray("params"); + request = params.toJSONString(); + } + if (method.equals("eth_sendRawTransaction")) { + jsonObject.put("Nc", "IN"); + headers = Headers.of(linkRawTransactionHeads); + request = jsonObject.toJSONString(); + } + RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE, request); + okhttp3.Request httpRequest; + httpRequest = new okhttp3.Request.Builder() + .url(url + method.replace("eth_", "")) + .headers(headers) + .post(requestBody) + .build(); + okhttp3.Response response = httpClient.newCall(httpRequest).execute(); + if (response.isSuccessful()) { + ResponseBody responseBody = response.body(); + if (responseBody != null) { + return buildInputStream(responseBody); + } else { + return null; + } + } else { + throw new ClientConnectionException( + "Invalid response received: " + response.body()); + } + } + + private InputStream buildInputStream(ResponseBody responseBody) throws IOException { + InputStream inputStream = responseBody.byteStream(); + + if (includeRawResponse) { + // we have to buffer the entire input payload, so that after processing + // it can be re-read and used to populate the rawResponse field. + + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body + Buffer buffer = source.buffer(); + + long size = buffer.size(); + if (size > Integer.MAX_VALUE) { + throw new UnsupportedOperationException( + "Non-integer input buffer size specified: " + size); + } + + int bufferSize = (int) size; + BufferedInputStream bufferedinputStream = + new BufferedInputStream(inputStream, bufferSize); + + bufferedinputStream.mark(inputStream.available()); + return bufferedinputStream; + + } else { + return inputStream; + } + } + + private Headers buildHeaders() { + return Headers.of(headers); + } + + public void addHeader(String key, String value) { + headers.put(key, value); + } + + public void addHeaders(Map headersToAdd) { + headers.putAll(headersToAdd); + } + + public HashMap getHeaders() { + return headers; + } +} \ No newline at end of file diff --git a/src/main/java/com/ethjava/LinkToken/LinkToken.java b/src/main/java/com/ethjava/LinkToken/LinkToken.java new file mode 100644 index 0000000..9c7ce3e --- /dev/null +++ b/src/main/java/com/ethjava/LinkToken/LinkToken.java @@ -0,0 +1,8 @@ +package com.ethjava.LinkToken; + +import org.web3j.protocol.core.Request; + +public interface LinkToken { + Request linkTransactionRecord(String address, int page, int count); + +} diff --git a/src/main/java/com/ethjava/LinkToken/LinkTransactionRecord.java b/src/main/java/com/ethjava/LinkToken/LinkTransactionRecord.java new file mode 100644 index 0000000..6251698 --- /dev/null +++ b/src/main/java/com/ethjava/LinkToken/LinkTransactionRecord.java @@ -0,0 +1,12 @@ +package com.ethjava.LinkToken; + +import org.web3j.protocol.core.Response; + +import java.util.List; + +public class LinkTransactionRecord extends Response> { + + public List getTransactionRecord() { + return getResult(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ethjava/LinkToken/TransactionRecord.java b/src/main/java/com/ethjava/LinkToken/TransactionRecord.java new file mode 100644 index 0000000..63d0e24 --- /dev/null +++ b/src/main/java/com/ethjava/LinkToken/TransactionRecord.java @@ -0,0 +1,169 @@ +package com.ethjava.LinkToken; + +public class TransactionRecord { + /** + * 转账金额 + */ + private String amount; + /** + * 交易所在区块 + */ + private String blocknum; + /** + * gas费用 + */ + private String cost; + /** + * 未知 + */ + private String execAccount; + /** + * 转账备注 + */ + private String extra; + /** + * 交易hash + */ + private String hash; + /** + * 未知 + */ + private String parent_hash; + /** + * 状态 1 成功 0 失败 + */ + private int status; + /** + * 上链时间(10位时间戳) + */ + private long timestamp; + /** + * 未知 + */ + private String title; + /** + * 对方地址 + */ + private String tradeAccount; + /** + * 0链克转出 1链克转入 2合约调用 + */ + private int type; + + public TransactionRecord() { + } + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getBlocknum() { + return blocknum; + } + + public void setBlocknum(String blocknum) { + this.blocknum = blocknum; + } + + public String getCost() { + return cost; + } + + public void setCost(String cost) { + this.cost = cost; + } + + public String getExecAccount() { + return execAccount; + } + + public void setExecAccount(String execAccount) { + this.execAccount = execAccount; + } + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getParent_hash() { + return parent_hash; + } + + public void setParent_hash(String parent_hash) { + this.parent_hash = parent_hash; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTradeAccount() { + return tradeAccount; + } + + public void setTradeAccount(String tradeAccount) { + this.tradeAccount = tradeAccount; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + @Override + public String toString() { + return "{" + + "amount:" + amount + + ",blocknum:" + blocknum + + ",cost:" + cost + + ",execAccount:" + execAccount + + ",extra:" + extra + + ",hash:" + hash + + ",parent_hash:" + parent_hash + + ",status:" + status + + ",timestamp:" + timestamp + + ",title:" + title + + ",tradeAccount:" + tradeAccount + + ",type:" + type + + "}\n"; + } +}