Java以太坊扫块和代币扫块

以太坊扫块

使用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,可以理解为这个代币的唯一标识
Java以太坊扫块和代币扫块_第1张图片
这样大家就能看出来一些差别了

 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中包含哪些内容

你可能感兴趣的:(区块链,扫块,ETH,代币)