使用geth搭建钱包服务器,博主使用的web3j客户端版本4.2.0
<dependency>
<groupId>org.web3jgroupId>
<artifactId>coreartifactId>
<version>4.2.0version>
dependency>
直接上代码,首先是获取当前最新高度的方法
/**
* 获得最新高度
* @return
* @throws Exception
*/
public Long getBlockNumber() {
long count = 0;
String stringObj = null;
try {
stringObj = send("eth_blockNumber", "[]");
JSONObject json = JSONObject.parseObject(stringObj);
if (json.containsKey("result")) {
count = Integer.parseInt(json.getString("result").substring(2), 16);
BigInteger valD = new BigInteger(json.getString("result").substring(2), 16);
return Long.parseLong(valD.toString(10));
}
} catch (Exception e) {
e.printStackTrace();
}
return count;
}
获取到最新高度之后要和历史高度对比(一般存在DB中,建议在缓存中也放一份,然后比较缓存和DB中的高度谁高用谁,我在omni扫usdt的文章中有)
public EthBlock getBlockEthBlock(Integer blockNumber) throws IOException {
DefaultBlockParameter defaultBlockParameter = new DefaultBlockParameterNumber(blockNumber);
Request<?, EthBlock> request = web3j.ethGetBlockByNumber(defaultBlockParameter, true);
EthBlock ethBlock = request.send();
return ethBlock;
}
上面的方法获取blockNumber块中的所有交易记录包含代币交易
List<EthBlock.TransactionResult> transactions= blockEthBlock.getResult().getTransactions();
for ( EthBlock.TransactionResult tx:transactions){
EthBlock.TransactionObject transaction = (EthBlock.TransactionObject) tx.get();
if(transaction.getValue().compareTo(BigInteger.ZERO)>0) {
if(Strings.isEmpty(transaction.getTo())){
log.info("转入地址为空跳过...");
continue;
}
int commit = currencyBlock-transaction.getBlockNumber().intValue()+1;
if(commit <= 5){
log.info("发现确认数小于5的数据,停止扫块");
flag = false;
break;
}
if(transaction.getTo().trim().equals(address)){
log.info("发现一笔充值........");
log.info("金额{}",toPrice(transaction.getValue()));
log.info("from{}",transaction.getFrom());
BigInteger gasPrice = transaction.getGasPrice().divide(new BigInteger("1000000000"));
BigInteger fee = gasPrice.multiply(transaction.getGas());
log.info("fee{}",df.format(fee.doubleValue()/1000000000).toString());
String txid = transaction.getHash().trim();
log.info("txid:{}",txid);
toMain(address,toPrice(transaction.getValue()));
}
//TO和我们的地址做比较
//如果有就继续判断hash有没有,没有就开始进行业务
}
}
上面就是核心的的扫块方法,和之前写的文章中一样也是从最新高度-1进行扫描,确认数可以根据你们的需求来定,最新块和当前块的差值就是确认数,transaction.getValue()>0就是ETH的交易,否则就算其他代币的交易,下面会继续讲如何扫代币,附上上面处理ETH金额精度的方法,这样得到的才是真实的ETH金额
public BigDecimal toPrice(BigInteger price){
//除18位小数
return new BigDecimal(price).divide(new BigDecimal(Math.pow(10,18))).setScale(6, RoundingMode.HALF_UP);
}
下面讲如何能扫到自己想要的代币,上面说过value<=0的就是ETH的代币,代币和正常的ETH交易信息不太一样,真实的到账地址,金额等都在input信息中,并不能通过transaction直接获取,我们以BTM代币(反正我没有用过这个)为例:
上面的合约地址其实就是contractId,可以理解为这个代币的唯一标识
这样大家就能看出来一些差别了
public String send(String method, String params)
throws Exception {
String tonce = "" + System.currentTimeMillis() * 1000L;
String url = web3jConfig.getUrl();
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Json-Rpc-Tonce", tonce.toString());
con.setRequestProperty("Content-Type", " application/json");
String postdata = "{\"jsonrpc\":\"2.0\",\"method\":\"" + method + "\", \"params\":" + params + ", \"id\": 1}";
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(postdata);
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
if (responseCode != 200) {
return "{\"result\":null,\"error\":" + responseCode + ",\"id\":1}";
}
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String result = in.readLine();
in.close();
return result;
}
上面是我封装了grpc的请求,你们也可以用其他方式,扫代币首先拿到当前块的hash,前提是在value<=0 也就是上面扫ETH的判断下面接一个else就可以
String hash = transaction.getHash();
String result = send("eth_getTransactionByHash",hash);
JSONObject json = JSONObject.parseObject(result);
//判断.....
return json.get("result");
通过上面的方式拿到代币的transaction,拿着上面的返回值就可以开始操作了
在下面的代码最上面要加一行transaction.getTo()然后和你想要找的代币合约地址做比较,否则是所有代币,代币合约地址可以去 https://www.yitaifang.com/tokens/ 里面找到你想要的代币合约地址
JSONObject jsonObject = JSON.parseObject(data.toString());
String from = jsonObject.getString("from");
String to = "0x"+jsonObject.getString("input").substring(34,74);
Double amount = parseAmount(jsonObject.getString("input").substring(78, jsonObject.getString("input").length()));
double gas = ethErcUtils.parseAmountNotws(jsonObject.getString("gas"));
double gasPrice = ethErcUtils.parseAmountNotws(jsonObject.getString("gasPrice"));
double fees = new BigDecimal(gas * gasPrice).setScale(6, BigDecimal.ROUND_HALF_DOWN).doubleValue();
BigDecimal fee = new BigDecimal(fees / Math.pow(10, 18)).setScale(6, BigDecimal.ROUND_HALF_DOWN);
String txid = jsonObject.getString("hash");
long blockNumber = Long.parseLong(jsonObject.getString("blockNumber").substring(2), 16);
log.info("-----代币交易------");
log.info("当前区块高度[{}]",blockNumber);
log.info("from:"+from+"to:"+to+"amount:"+amount,"fee:"+fee+"txid:"+txid);
以上就是扫代币的方式,不用两个定时job,扫一次就可以通过if else去分别做业务
结尾别忘记了扫完增加高度,并把当前高度存入到数据库
index++;
这里只讲扫块,上面有个toMain方法是汇总,等下次有时间写一下关于ETH汇总和转账.,这里没有讲为什么这么subString,感兴趣的可以去了解一下input中包含哪些内容