From 218df35e1e8b89447fe7d3c1ca6f3a29f8f89755 Mon Sep 17 00:00:00 2001
From: xiaoyong931011 <15274802129@163.com>
Date: Sat, 31 Dec 2022 02:02:58 +0800
Subject: [PATCH] 20221227 充值归集

---
 src/main/java/cc/mrbird/febs/mall/chain/job/ChainListenerJob.java           |   88 ++++
 src/main/java/cc/mrbird/febs/mall/chain/service/ChainService.java           |  185 +++++++++
 src/test/java/cc/mrbird/febs/ProfitTest.java                                |   25 +
 src/main/java/cc/mrbird/febs/mall/service/impl/BlockSeriveImpl.java         |    1 
 src/main/java/cc/mrbird/febs/mall/chain/service/UsdtErc20UpdateService.java |    2 
 src/main/java/cc/mrbird/febs/mall/chain/service/ContractEventService.java   |    6 
 pom.xml                                                                     |    5 
 src/main/java/cc/mrbird/febs/mall/chain/service/BscUsdtContractEvent.java   |  138 +++++++
 src/main/java/cc/mrbird/febs/mall/chain/service/BlockCoinServiceImpl.java   |   12 
 src/main/java/cc/mrbird/febs/mall/chain/service/ContractChainService.java   |   31 +
 src/main/java/cc/mrbird/febs/mall/chain/enums/ChainEnum.java                |   54 ++
 src/main/java/cc/mrbird/febs/mall/chain/service/BaseCoinService.java        |  135 +++++++
 src/main/java/cc/mrbird/febs/common/utils/AppContants.java                  |    3 
 src/main/java/cc/mrbird/febs/mall/chain/enums/EthService.java               |  433 ++++++++++++++++++++++
 src/main/java/cc/mrbird/febs/mall/chain/service/EthService.java             |   10 
 15 files changed, 1,114 insertions(+), 14 deletions(-)

diff --git a/pom.xml b/pom.xml
index dd93c07..ebdbe02 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,11 @@
     </properties>
 
     <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.web3j</groupId>
             <artifactId>core</artifactId>
diff --git a/src/main/java/cc/mrbird/febs/common/utils/AppContants.java b/src/main/java/cc/mrbird/febs/common/utils/AppContants.java
index 79d69c3..0374bd5 100644
--- a/src/main/java/cc/mrbird/febs/common/utils/AppContants.java
+++ b/src/main/java/cc/mrbird/febs/common/utils/AppContants.java
@@ -67,5 +67,8 @@
 
     public static final String AGENT_LEVEL = "AGENT_LEVEL";
     public static final String AGENT_LEVEL_REQUIRE = "AGENT_LEVEL_REQUIRE";
+    public static final String REDIS_KEY_BLOCK_USDT_NUM = "BLOCK_USDT_NUM";
+    public static final String REDIS_KEY_BLOCK_ETH_INCREMENT_NUM = "BLOCK_ETH_INCREMENT_NUM";
+    public static final String REDIS_KEY_BLOCK_ETH_NEWEST_NUM = "BLOCK_ETH_NEWEST_NUM";
 
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/enums/ChainEnum.java b/src/main/java/cc/mrbird/febs/mall/chain/enums/ChainEnum.java
new file mode 100644
index 0000000..c1353cb
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/enums/ChainEnum.java
@@ -0,0 +1,54 @@
+package cc.mrbird.febs.mall.chain.enums;
+
+import lombok.Getter;
+
+/**
+ * 链类型
+ */
+@Getter
+public enum ChainEnum {
+
+    /**
+     * 币安 usdt合约
+     * 0x55d398326f99059fF775485246999027B3197955
+     * 测试链 0x337610d27c682E347C9cD60BD4b3b107C9d34dDd
+     */
+    BSC_USDT("BSC", "0x7FC948E091C4b71fC063cE59B8Dad1062B1c5065",
+            "0xbf6f11f5689961d5351375bebbae751de0d0d5c2e2095c1017368485dc909ff8",
+            "https://bsc-dataseed1.ninicoin.io",
+            "0x55d398326f99059fF775485246999027B3197955",
+            "");
+
+
+    private String chain;
+
+    private String address;
+
+    private String privateKey;
+
+    private String url;
+
+    private String contractAddress;
+
+    private String apiKey;
+
+    ChainEnum(String chain, String address, String privateKey, String url, String contractAddress, String apiKey) {
+        this.chain = chain;
+        this.address = address;
+        this.privateKey = privateKey;
+        this.url = url;
+        this.contractAddress = contractAddress;
+        this.apiKey = apiKey;
+    }
+
+    public static ChainEnum getValueByName(String name) {
+        ChainEnum[] values = values();
+        for (ChainEnum value : values) {
+            if (value.name().equals(name)) {
+                return value;
+            }
+        }
+
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/enums/EthService.java b/src/main/java/cc/mrbird/febs/mall/chain/enums/EthService.java
new file mode 100644
index 0000000..4cbecc8
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/enums/EthService.java
@@ -0,0 +1,433 @@
+package cc.mrbird.febs.mall.chain.enums;
+
+import cc.mrbird.febs.mall.chain.service.ContractChainService;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+import org.web3j.abi.FunctionEncoder;
+import org.web3j.abi.FunctionReturnDecoder;
+import org.web3j.abi.TypeReference;
+import org.web3j.abi.datatypes.Address;
+import org.web3j.abi.datatypes.Function;
+import org.web3j.abi.datatypes.Type;
+import org.web3j.abi.datatypes.generated.Uint256;
+import org.web3j.crypto.Credentials;
+import org.web3j.crypto.RawTransaction;
+import org.web3j.crypto.TransactionEncoder;
+import org.web3j.protocol.Web3j;
+import org.web3j.protocol.core.DefaultBlockParameterName;
+import org.web3j.protocol.core.Request;
+import org.web3j.protocol.core.methods.request.Transaction;
+import org.web3j.protocol.core.methods.response.EthBlockNumber;
+import org.web3j.protocol.core.methods.response.EthCall;
+import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
+import org.web3j.protocol.core.methods.response.EthSendTransaction;
+import org.web3j.protocol.http.HttpService;
+import org.web3j.utils.Convert;
+import org.web3j.utils.Numeric;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * @author wzy
+ * @date 2022-04-15
+ **/
+public class EthService implements ContractChainService {
+
+    private Web3j web3j;
+    private String url;
+    private String ownerAddress;
+    private String privateKey;
+    private String contractAddress;
+
+    public EthService(String url, String address, String privateKey, String contractAddress) {
+        this.url = url;
+        this.ownerAddress = address;
+        this.privateKey = privateKey;
+        this.contractAddress = contractAddress;
+
+        HttpService service = new HttpService(url);
+        web3j = Web3j.build(service);
+    }
+
+    public static void main(String[] args) throws IOException {
+        HttpService service = new HttpService("https://bsc-dataseed1.ninicoin.io");
+        Web3j web3j = Web3j.build(service);
+        long start = System.currentTimeMillis();
+        Request<?, EthBlockNumber> request = web3j.ethBlockNumber();
+        EthBlockNumber send = request.send();
+        BigInteger bigInteger = Numeric.decodeQuantity(send.getResult());
+        long end = System.currentTimeMillis();
+        System.out.println(end - start);
+
+//        String address = "0x971c09aa9735eb98459b17ec8b48932d24cbb931";
+//        String nonce = "0x1d5f7444107bc02e980deda39d0fce21b06c9da4233a19cb11124cb5bfefc9ec";
+//        String sign = "0x8f92cee24906122e26c3cc6cbd72f851cfe2c9574aa03bf3371e5d506fbec68b2ad22bbbc19b00ed21d26ab5a6871507831e2c902d8ed8c33301addc2b57a7731b";
+//
+//        String result = address + ":" + nonce + ":" + sign;
+//        System.out.println(Hash.sha3(result));
+
+
+//        Web3Sha3 send = web3j.web3Sha3(result).send();
+//        System.out.println(1);
+    }
+
+    @Override
+    public BigInteger balanceOfUnDecimal(String fromAddress) {
+        try {
+            String methodName = "balanceOf";
+            List<Type> inputParameters = new ArrayList<>();
+            List<TypeReference<?>> outputParameters = new ArrayList<>();
+            Address address = new Address(fromAddress);
+            inputParameters.add(address);
+            TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
+            };
+            outputParameters.add(typeReference);
+            Function function = new Function(methodName, inputParameters, outputParameters);
+            String data = FunctionEncoder.encode(function);
+            Transaction transaction = Transaction.createEthCallTransaction(fromAddress, contractAddress, data);
+
+            EthCall ethCall;
+            BigInteger balanceValue = BigInteger.ZERO;
+            try {
+                ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
+                List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
+                balanceValue = (BigInteger) results.get(0).getValue();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+            return balanceValue;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return BigInteger.ZERO;
+    }
+
+    @Override
+    public int decimals() {
+        try {
+            String methodName = "decimals";
+            List<Type> inputParameters = new ArrayList<>();
+            List<TypeReference<?>> outputParameters = new ArrayList<>();
+            TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
+            };
+            outputParameters.add(typeReference);
+            Function function = new Function(methodName, inputParameters, outputParameters);
+            String data = FunctionEncoder.encode(function);
+            Transaction transaction = Transaction.createEthCallTransaction(null, contractAddress, data);
+
+            EthCall ethCall;
+            BigInteger decimals = BigInteger.ZERO;
+            try {
+                ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
+                List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
+                decimals = (BigInteger) results.get(0).getValue();
+                return decimals.intValue();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    @Override
+    public BigDecimal balanceOf(String fromAddress) {
+        int decimal = decimals();
+        BigInteger balanceValue = balanceOfUnDecimal(fromAddress);
+
+        double res = new BigDecimal(balanceValue).divide(BigDecimal.valueOf(Math.pow(10, decimal)), 8, RoundingMode.HALF_DOWN).doubleValue();
+        if (res > 0) {
+            return new BigDecimal(res);
+        }
+
+        return BigDecimal.ZERO;
+    }
+
+    @Override
+    public BigInteger allowance(String address) {
+        String methodName = "allowance";
+        List<TypeReference<?>> outputParameters = new ArrayList<>();
+        TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
+        };
+        outputParameters.add(typeReference);
+
+        Function function = new Function(methodName,
+                Arrays.asList(new Address(address), new Address(ownerAddress))
+                , outputParameters);
+        String data = FunctionEncoder.encode(function);
+        Transaction transaction = Transaction.createEthCallTransaction(ownerAddress, contractAddress, data);
+
+        EthCall ethCall = null;
+        try {
+            ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
+            List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
+            return (BigInteger) results.get(0).getValue();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return BigInteger.ZERO;
+    }
+
+    @Override
+    public boolean isAllowance(String address) {
+        return allowance(address).intValue() != 0;
+    }
+
+    public String getGas() {
+        String gas;
+        if (url.contains("infura.io")) {
+            String resp = HttpUtil.get("https://etherscan.io/autoUpdateGasTracker.ashx?sid=75f30b765180f29e2b7584b8501c9124");
+            JSONObject data = JSONObject.parseObject(resp);
+            gas = data.getString("avgPrice");
+        } else {
+            String resp = HttpUtil.get("https://gbsc.blockscan.com/gasapi.ashx?apikey=key&method=gasoracle");
+            JSONObject data = JSONObject.parseObject(resp);
+            gas = data.getString("FastGasPrice");
+        }
+        return StrUtil.isBlank(gas) ? "35" : gas;
+    }
+
+    @Override
+    public String transfer(String address) {
+        BigDecimal balance = balanceOf(address);
+
+        return transfer(address, balance);
+    }
+
+    @Override
+    public String transfer(String address, BigDecimal amount) {
+        try {
+            return tokenTransfer(privateKey, ownerAddress, address, amount.toPlainString());
+        } catch (ExecutionException | InterruptedException e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    public String tokenTransferFrom(String privateKey, String fromAddress, String toAddress, String amount) throws ExecutionException, InterruptedException {
+        String gas = getGas();
+
+        BigDecimal amountPow = new BigDecimal(amount).multiply(BigDecimal.TEN.pow(decimals()));
+        amount = amountPow.toPlainString();
+        if (amount.contains(".")) {
+            amount = amount.substring(0, amount.lastIndexOf("."));
+        }
+
+        Credentials credentials = Credentials.create(privateKey);
+
+        EthGetTransactionCount ethGetTransactionCount = web3j
+                .ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
+
+        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
+
+        Function function = new Function("transferFrom",
+                Arrays.asList(new Address(fromAddress), new Address(toAddress), new Uint256(new BigInteger(amount))),
+                Arrays.asList(new TypeReference<Type>() {
+                }));
+
+        String encodedFunction = FunctionEncoder.encode(function);
+
+        RawTransaction rawTransaction = RawTransaction.createTransaction(nonce,
+                Convert.toWei(gas, Convert.Unit.GWEI).toBigInteger(),// 给矿工开的转账单价 单价越高越快
+                Convert.toWei("100000", Convert.Unit.WEI).toBigInteger(), contractAddress, encodedFunction);//里程上限
+
+        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
+        String hexValue = Numeric.toHexString(signedMessage);
+
+        CompletableFuture<EthSendTransaction> ethSendTransactionCompletableFuture = web3j.ethSendRawTransaction(hexValue).sendAsync();
+        EthSendTransaction ethSendTransaction = ethSendTransactionCompletableFuture.get();
+
+
+        if (ethSendTransaction.hasError()) {
+            return "";
+        } else {
+            return ethSendTransaction.getTransactionHash();
+        }
+    }
+
+    public String tokenTransfer(String privateKey, String fromAddress, String toAddress, String amount) throws ExecutionException, InterruptedException {
+        String gas = getGas();
+
+        BigDecimal amountPow = new BigDecimal(amount).multiply(BigDecimal.TEN.pow(decimals()));
+        amount = amountPow.toPlainString();
+        if (amount.contains(".")) {
+            amount = amount.substring(0, amount.lastIndexOf("."));
+        }
+
+        Credentials credentials = Credentials.create(privateKey);
+
+        EthGetTransactionCount ethGetTransactionCount = web3j
+                .ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
+
+        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
+
+        Function function = new Function("transfer",
+                Arrays.asList(new Address(toAddress), new Uint256(new BigInteger(amount))),
+                Arrays.asList(new TypeReference<Type>() {
+                }));
+
+        String encodedFunction = FunctionEncoder.encode(function);
+
+        RawTransaction rawTransaction = RawTransaction.createTransaction(nonce,
+                Convert.toWei(gas, Convert.Unit.GWEI).toBigInteger(),// 给矿工开的转账单价 单价越高越快
+                Convert.toWei("100000", Convert.Unit.WEI).toBigInteger(), contractAddress, encodedFunction);//里程上限
+
+        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
+        String hexValue = Numeric.toHexString(signedMessage);
+
+        CompletableFuture<EthSendTransaction> ethSendTransactionCompletableFuture = web3j.ethSendRawTransaction(hexValue).sendAsync();
+        EthSendTransaction ethSendTransaction = ethSendTransactionCompletableFuture.get();
+
+
+        if (ethSendTransaction.hasError()) {
+            return "";
+        } else {
+            return ethSendTransaction.getTransactionHash();
+        }
+    }
+
+    @Override
+    public int allowanceCnt(String address) {
+        String allowanceUrl;
+        if (url.contains("infura.io")) {
+            allowanceUrl = "https://etherscan.io/tokenapprovalchecker.aspx/GetApprovedContract";
+        } else {
+            allowanceUrl = "https://bscscan.com/tokenapprovalchecker.aspx/GetApprovedContract";
+        }
+
+        String baseData = "{\"dataTableModel\":{\"draw\":3,\"columns\":[{\"data\":\"TxnHash\",\"name\":\"\",\"searchable\":true,\"orderable\":false,\"search\":{\"value\":\"\",\"regex\":false}},{\"data\":\"Block\",\"name\":\"\",\"searchable\":true,\"orderable\":false,\"search\":{\"value\":\"\",\"regex\":false}},{\"data\":\"Token\",\"name\":\"\",\"searchable\":true,\"orderable\":false,\"search\":{\"value\":\"\",\"regex\":false}},{\"data\":\"ApprovedSpender\",\"name\":\"\",\"searchable\":true,\"orderable\":false,\"search\":{\"value\":\"\",\"regex\":false}},{\"data\":\"ApprovedAmount\",\"name\":\"\",\"searchable\":true,\"orderable\":false,\"search\":{\"value\":\"\",\"regex\":false}},{\"data\":\"LastUpdated\",\"name\":\"\",\"searchable\":true,\"orderable\":false,\"search\":{\"value\":\"\",\"regex\":false}},{\"data\":\"Action\",\"name\":\"\",\"searchable\":true,\"orderable\":false,\"search\":{\"value\":\"\",\"regex\":false}}],\"order\":[],\"start\":0,\"length\":25,\"search\":{\"value\":\"\",\"regex\":false}},\"model\":{\"address\":\"{address}\",\"filteredContract\":\"\"}}";
+        String data = baseData.replace("{address}", address);
+
+        String resp = HttpUtil.post(allowanceUrl, data);
+
+        JSONObject jsonObject = JSONObject.parseObject(resp);
+        JSONObject result = JSONObject.parseObject(jsonObject.getString("d"));
+        return result.getIntValue("recordsTotal");
+    }
+
+    @Override
+    public BigInteger blockNumber() {
+        Request<?, EthBlockNumber> request = web3j.ethBlockNumber();
+        EthBlockNumber send = null;
+        try {
+            send = request.send();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        if (send != null) {
+            return Numeric.decodeQuantity(send.getResult());
+        } else {
+            throw new NullPointerException();
+        }
+    }
+
+    @Override
+    public BigInteger totalSupply() {
+        try {
+            String methodName = "totalSupply";
+            List<Type> inputParameters = new ArrayList<>();
+            List<TypeReference<?>> outputParameters = new ArrayList<>();
+            TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
+            };
+            outputParameters.add(typeReference);
+            Function function = new Function(methodName, inputParameters, outputParameters);
+            String data = FunctionEncoder.encode(function);
+            Transaction transaction = Transaction.createEthCallTransaction(null, contractAddress, data);
+
+            EthCall ethCall;
+            BigInteger totalSupply = BigInteger.ZERO;
+            try {
+                ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
+                List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
+                totalSupply = (BigInteger) results.get(0).getValue();
+                return totalSupply.divide(BigInteger.TEN.pow(decimals()));
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return BigInteger.ZERO;
+    }
+
+    @Override
+    public BigInteger totalSupplyNFT() {
+        try {
+            String methodName = "totalSupply";
+            List<Type> inputParameters = new ArrayList<>();
+            List<TypeReference<?>> outputParameters = new ArrayList<>();
+            TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
+            };
+            outputParameters.add(typeReference);
+            Function function = new Function(methodName, inputParameters, outputParameters);
+            String data = FunctionEncoder.encode(function);
+            Transaction transaction = Transaction.createEthCallTransaction(null, contractAddress, data);
+
+            EthCall ethCall;
+            BigInteger totalSupply = BigInteger.ZERO;
+            try {
+                ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
+                List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
+                totalSupply = (BigInteger) results.get(0).getValue();
+                return totalSupply;
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return BigInteger.ZERO;
+    }
+
+    @Override
+    public String safeMintNFT(String toAddress) {
+        String gas = getGas();
+
+        try {
+            Credentials credentials = Credentials.create(privateKey);
+            EthGetTransactionCount ethGetTransactionCount = web3j
+                    .ethGetTransactionCount(ownerAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
+            BigInteger nonce = ethGetTransactionCount.getTransactionCount();
+            Function function = new Function("safeMint",
+                    Arrays.asList(new Address(toAddress)),
+                    Arrays.asList(new TypeReference<Type>() {
+                    }));
+
+            String encodedFunction = FunctionEncoder.encode(function);
+            RawTransaction rawTransaction = RawTransaction.createTransaction(nonce,
+                    Convert.toWei(gas, Convert.Unit.GWEI).toBigInteger(),
+                    Convert.toWei("1000000", Convert.Unit.WEI).toBigInteger(), contractAddress, encodedFunction);
+
+            byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
+            String hexValue = Numeric.toHexString(signedMessage);
+
+            CompletableFuture<EthSendTransaction> ethSendTransactionCompletableFuture = web3j.ethSendRawTransaction(hexValue).sendAsync();
+            EthSendTransaction ethSendTransaction = ethSendTransactionCompletableFuture.get();
+
+            if (ethSendTransaction.hasError()) {
+                return "";
+            } else {
+                return ethSendTransaction.getTransactionHash();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/job/ChainListenerJob.java b/src/main/java/cc/mrbird/febs/mall/chain/job/ChainListenerJob.java
new file mode 100644
index 0000000..b6ad5c3
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/job/ChainListenerJob.java
@@ -0,0 +1,88 @@
+package cc.mrbird.febs.mall.chain.job;
+
+import cc.mrbird.febs.common.utils.AppContants;
+import cc.mrbird.febs.common.utils.RedisUtils;
+import cc.mrbird.febs.mall.chain.enums.ChainEnum;
+import cc.mrbird.febs.mall.chain.service.BaseCoinService;
+import cc.mrbird.febs.mall.chain.service.BscUsdtContractEvent;
+import cc.mrbird.febs.mall.chain.service.ChainService;
+import cc.mrbird.febs.mall.chain.service.ContractEventService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.math.BigInteger;
+
+@Slf4j
+@Component
+@ConditionalOnProperty(prefix = "system", name = "chain-listener", havingValue = "true")
+public class ChainListenerJob implements ApplicationRunner {
+
+    @Autowired
+    private ContractEventService bscUsdtContractEvent;
+
+    @Autowired
+    private RedisUtils redisUtils;
+
+    @Autowired
+    private BaseCoinService baseCoinService;
+
+    @Scheduled(cron = "0 0/5 * * * ? ")
+    public void chainBlockUpdate() {
+        BigInteger blockNumber = ChainService.getInstance(ChainEnum.BSC_USDT.name()).blockNumber();
+
+        redisUtils.set(AppContants.REDIS_KEY_BLOCK_ETH_NEWEST_NUM, blockNumber);
+    }
+
+    @Scheduled(cron = "0/2 * * * * ? ")
+    public void chainIncrementBlock() {
+        Object newestBlockObj = redisUtils.get(AppContants.REDIS_KEY_BLOCK_ETH_NEWEST_NUM);
+        BigInteger newestBlock;
+        if (newestBlockObj == null) {
+            newestBlock = ChainService.getInstance(ChainEnum.BSC_USDT.name()).blockNumber();
+        } else {
+            newestBlock = (BigInteger) newestBlockObj;
+        }
+
+        Object incrementObj = redisUtils.get(AppContants.REDIS_KEY_BLOCK_ETH_INCREMENT_NUM);
+        BigInteger toIncrement;
+        if (incrementObj == null) {
+            toIncrement = newestBlock;
+        } else {
+            BigInteger incrementBlock = (BigInteger) incrementObj;
+
+            // 最新区块小于增加区块
+            if (newestBlock.compareTo(incrementBlock) <= 0) {
+                return;
+            }
+            toIncrement = incrementBlock.add(BigInteger.ONE);
+        }
+
+        redisUtils.set(AppContants.REDIS_KEY_BLOCK_ETH_INCREMENT_NUM, toIncrement);
+    }
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        long start = System.currentTimeMillis();
+        log.info("区块链监听开始启动");
+        Object incrementObj = redisUtils.get(AppContants.REDIS_KEY_BLOCK_ETH_INCREMENT_NUM);
+        BigInteger newest = ChainService.getInstance(ChainEnum.BSC_USDT.name()).blockNumber();
+        BigInteger block;
+        if (incrementObj == null) {
+            block = newest;
+        } else {
+            block = (BigInteger) incrementObj;
+        }
+
+
+//        ChainService.wssBaseCoinEventListener(block, baseCoinService);
+//        ChainService.wssBaseCoinEventListener(block, bscUsdtContractEvent);
+        ChainService.wssContractEventListener(block, bscUsdtContractEvent, ChainEnum.BSC_USDT.name());
+        long end = System.currentTimeMillis();
+        log.info("区块链监听启动完成, 消耗时间{}", end - start);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/BaseCoinService.java b/src/main/java/cc/mrbird/febs/mall/chain/service/BaseCoinService.java
new file mode 100644
index 0000000..0f7332c
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/BaseCoinService.java
@@ -0,0 +1,135 @@
+package cc.mrbird.febs.mall.chain.service;
+
+import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
+import cc.mrbird.febs.common.enumerates.MallMoneyFlowTypeEnum;
+import cc.mrbird.febs.common.utils.AppContants;
+import cc.mrbird.febs.common.utils.RedisUtils;
+import cc.mrbird.febs.mall.chain.enums.ChainEnum;
+import cc.mrbird.febs.mall.chain.enums.CoinTypeEnum;
+import cc.mrbird.febs.mall.entity.MallMemberWallet;
+import cc.mrbird.febs.mall.entity.MallMoneyFlow;
+import cc.mrbird.febs.mall.entity.MemberCoinAddressEntity;
+import cc.mrbird.febs.mall.entity.MemberCoinChargeEntity;
+import cc.mrbird.febs.mall.mapper.MallMemberWalletMapper;
+import cc.mrbird.febs.mall.mapper.MemberCoinAddressDao;
+import cc.mrbird.febs.mall.mapper.MemberCoinChargeDao;
+import cc.mrbird.febs.mall.service.IMallMoneyFlowService;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.stereotype.Service;
+import org.web3j.protocol.core.methods.response.Transaction;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class BaseCoinService {
+
+    @Resource
+    private RedisUtils redisUtils;
+    @Resource
+    private MemberCoinChargeDao memberCoinChargeDao;
+    @Resource
+    private MemberCoinAddressDao memberCoinAddressDao;
+    @Resource
+    private MallMemberWalletMapper mallMemberWalletMapper;
+    @Resource
+    private IMallMoneyFlowService mallMoneyFlowService;
+
+    public void compile(Transaction e) {
+        if (e.getTo() == null) {
+            return;
+        }
+
+        redisUtils.set(AppContants.REDIS_KEY_BLOCK_USDT_NUM, e.getBlockNumber());
+
+        String address = e.getTo();
+        String hash =  e.getHash();
+        MemberCoinAddressEntity coinAddressEntity = memberCoinAddressDao.selectCoinAddressByAddressAndSymbol(address, CoinTypeEnum.USDT.toString());
+        if (coinAddressEntity == null) {
+            return;
+        }
+        // 判断对方打款地址是否为源池地址
+        if(ObjectUtil.isNotEmpty(coinAddressEntity)){
+//        if (ChainEnum.BSC_USDT.getAddress().toLowerCase().equals(e.to)) {
+            log.info("触发USDT合约监听事件");
+            redisUtils.set(AppContants.REDIS_KEY_BLOCK_ETH_INCREMENT_NUM, e.getBlockNumber());
+            // hash没有用过
+            Map<String, Object> param = new HashMap<>();
+            param.put("hash", hash);
+            param.put("address", address);
+            List<MemberCoinChargeEntity> memberCoinChargeEntities = memberCoinChargeDao.selectByMap(param);
+            if (CollectionUtils.isNotEmpty(memberCoinChargeEntities)) {
+                return;
+            }
+
+//            MemberCoinAddressEntity coinAddressEntity = memberCoinAddressDao.selectCoinAddressByAddressAndSymbol(address, CoinTypeEnum.USDT.toString());
+//            if (coinAddressEntity == null) {
+//                return;
+//            }
+            Long memberId = coinAddressEntity.getMemberId();
+            BigDecimal amount = new BigDecimal(e.getValue()).divide(BigDecimal.TEN.pow(18), 8, RoundingMode.HALF_DOWN);
+            BigDecimal balance = amount;
+            if (balance != null && balance.compareTo(new BigDecimal("0.1")) > 0) {
+                balance = balance.setScale(8, RoundingMode.CEILING);
+                BigDecimal early = BigDecimal.ZERO;
+                // 查询钱包 并更新
+                MallMemberWallet mallMemberWallet = mallMemberWalletMapper.selectWalletByMemberId(memberId);
+                if (mallMemberWallet == null) {
+                    return;
+                }
+
+                mallMemberWalletMapper.updateBlockBalanceById(mallMemberWallet.getId(), balance);
+
+                String orderNo = insertCoinCharge(address, memberId, balance, CoinTypeEnum.USDT.name(), "ERC20", BigDecimal.ZERO, hash);
+                // 插入财务记录
+
+                Long chargeFlowId = mallMoneyFlowService.addMoneyFlow(
+                        memberId,
+                        orderNo,
+                        balance.setScale(4, BigDecimal.ROUND_DOWN),
+                        MallMoneyFlowTypeEnum.CHARGE.getCode(),
+                        MallMoneyFlow.STATUS_SUCCESS,
+                        MallMoneyFlow.IS_RETURN_Y,
+                        memberId,
+                        FlowTypeEnum.BALANCE.getValue(),
+                        MallMoneyFlowTypeEnum.CHARGE.getName()
+                );
+                // 同步
+//                BigDecimal bigDecimal = ChainService.getInstance(ChainEnum.BSC_USDT.name()).balanceOf(e.to);
+
+            }
+
+
+        }
+    }
+    public String insertCoinCharge(String address, Long memberId, BigDecimal newBalance, String symbol, String tag, BigDecimal lastAmount, String hash) {
+        MemberCoinChargeEntity memberCoinChargeEntity = new MemberCoinChargeEntity();
+        memberCoinChargeEntity.setAddress(address);
+        memberCoinChargeEntity.setMemberId(memberId);
+        memberCoinChargeEntity.setAmount(newBalance);
+        memberCoinChargeEntity.setSymbol(symbol);
+        memberCoinChargeEntity.setTag(tag);
+        memberCoinChargeEntity.setStatus(1);
+        memberCoinChargeEntity.setLastAmount(lastAmount);
+        memberCoinChargeEntity.setHash(hash);
+        String orderNo = generateNo();
+        memberCoinChargeEntity.setOrderCode(orderNo);
+        memberCoinChargeDao.insert(memberCoinChargeEntity);
+        return orderNo;
+    }
+    private String generateNo() {
+        // 生成订单号
+        Long timestamp = System.currentTimeMillis();
+        // 随机数
+        int random = (int) (Math.random() * 10);
+        return String.valueOf(timestamp).substring(2) + random;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/BlockCoinServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/chain/service/BlockCoinServiceImpl.java
index 0660317..be364b5 100644
--- a/src/main/java/cc/mrbird/febs/mall/chain/service/BlockCoinServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/BlockCoinServiceImpl.java
@@ -114,12 +114,12 @@
             return;
         }
         // 校验这个交易是否成功
-        EthService ethService = new EthService();
-        boolean b = ethService.checkTransferResult(hash);
-        if (!b) {
-            log.info("#USDT假充值:{}#", hash);
-            return;
-        }
+//        EthService ethService = new EthService();
+//        boolean b = ethService.checkTransferResult(hash);
+//        if (!b) {
+//            log.info("#USDT假充值:{}#", hash);
+//            return;
+//        }
         MemberCoinAddressEntity coinAddressEntity = memberCoinAddressDao.selectCoinAddressByAddressAndSymbol(address, CoinTypeEnum.USDT.toString());
         if (coinAddressEntity == null) {
             return;
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/BscUsdtContractEvent.java b/src/main/java/cc/mrbird/febs/mall/chain/service/BscUsdtContractEvent.java
new file mode 100644
index 0000000..fcffcac
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/BscUsdtContractEvent.java
@@ -0,0 +1,138 @@
+package cc.mrbird.febs.mall.chain.service;
+
+import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
+import cc.mrbird.febs.common.enumerates.MallMoneyFlowTypeEnum;
+import cc.mrbird.febs.common.utils.AppContants;
+import cc.mrbird.febs.common.utils.RedisUtils;
+import cc.mrbird.febs.mall.chain.enums.ChainEnum;
+import cc.mrbird.febs.mall.chain.enums.CoinTypeEnum;
+import cc.mrbird.febs.mall.entity.MallMemberWallet;
+import cc.mrbird.febs.mall.entity.MallMoneyFlow;
+import cc.mrbird.febs.mall.entity.MemberCoinAddressEntity;
+import cc.mrbird.febs.mall.entity.MemberCoinChargeEntity;
+import cc.mrbird.febs.mall.mapper.MallMemberWalletMapper;
+import cc.mrbird.febs.mall.mapper.MemberCoinAddressDao;
+import cc.mrbird.febs.mall.mapper.MemberCoinChargeDao;
+import cc.mrbird.febs.mall.service.IMallMoneyFlowService;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class BscUsdtContractEvent implements ContractEventService {
+
+    @Resource
+    private RedisUtils redisUtils;
+    @Resource
+    private MemberCoinChargeDao memberCoinChargeDao;
+    @Resource
+    private MemberCoinAddressDao memberCoinAddressDao;
+    @Resource
+    private MallMemberWalletMapper mallMemberWalletMapper;
+    @Resource
+    private IMallMoneyFlowService mallMoneyFlowService;
+
+    @Override
+    public void compile(EthUsdtContract.TransferEventResponse e) {
+        if (e.to == null) {
+            return;
+        }
+
+        redisUtils.set(AppContants.REDIS_KEY_BLOCK_USDT_NUM, e.log.getBlockNumber());
+
+        String address = e.to;
+        String hash =  e.log.getTransactionHash();
+        MemberCoinAddressEntity coinAddressEntity = memberCoinAddressDao.selectCoinAddressByAddressAndSymbol(address, CoinTypeEnum.USDT.toString());
+        if (coinAddressEntity == null) {
+            return;
+        }
+        // 判断对方打款地址是否为源池地址
+        if(ObjectUtil.isNotEmpty(coinAddressEntity)){
+//        if (ChainEnum.BSC_USDT.getAddress().toLowerCase().equals(e.to)) {
+            log.info("触发USDT合约监听事件");
+            redisUtils.set(AppContants.REDIS_KEY_BLOCK_ETH_INCREMENT_NUM, e.log.getBlockNumber());
+            // hash没有用过
+            Map<String, Object> param = new HashMap<>();
+            param.put("hash", hash);
+            param.put("address", address);
+            List<MemberCoinChargeEntity> memberCoinChargeEntities = memberCoinChargeDao.selectByMap(param);
+            if (CollectionUtils.isNotEmpty(memberCoinChargeEntities)) {
+                return;
+            }
+
+//            MemberCoinAddressEntity coinAddressEntity = memberCoinAddressDao.selectCoinAddressByAddressAndSymbol(address, CoinTypeEnum.USDT.toString());
+//            if (coinAddressEntity == null) {
+//                return;
+//            }
+            Long memberId = coinAddressEntity.getMemberId();
+            ContractChainService sourceUsdtInstance = ChainService.getInstance(ChainEnum.BSC_USDT.name());
+            int decimals = sourceUsdtInstance.decimals();
+            BigInteger tokens = e.tokens;
+            BigDecimal amount = new BigDecimal(tokens.toString()).divide(BigDecimal.TEN.pow(decimals), decimals, RoundingMode.HALF_DOWN);
+            BigDecimal balance = amount;
+            if (balance != null && balance.compareTo(new BigDecimal("0.1")) > 0) {
+                balance = balance.setScale(8, RoundingMode.CEILING);
+                BigDecimal early = BigDecimal.ZERO;
+                // 查询钱包 并更新
+                MallMemberWallet mallMemberWallet = mallMemberWalletMapper.selectWalletByMemberId(memberId);
+                if (mallMemberWallet == null) {
+                    return;
+                }
+
+                mallMemberWalletMapper.updateBlockBalanceById(mallMemberWallet.getId(), balance);
+
+                String orderNo = insertCoinCharge(address, memberId, balance, CoinTypeEnum.USDT.name(), "ERC20", BigDecimal.ZERO, hash);
+                // 插入财务记录
+
+                Long chargeFlowId = mallMoneyFlowService.addMoneyFlow(
+                        memberId,
+                        orderNo,
+                        balance.setScale(4, BigDecimal.ROUND_DOWN),
+                        MallMoneyFlowTypeEnum.CHARGE.getCode(),
+                        MallMoneyFlow.STATUS_SUCCESS,
+                        MallMoneyFlow.IS_RETURN_Y,
+                        memberId,
+                        FlowTypeEnum.BALANCE.getValue(),
+                        MallMoneyFlowTypeEnum.CHARGE.getName()
+                );
+                // 同步
+//                BigDecimal bigDecimal = ChainService.getInstance(ChainEnum.BSC_USDT.name()).balanceOf(e.to);
+
+            }
+
+
+        }
+    }
+    public String insertCoinCharge(String address, Long memberId, BigDecimal newBalance, String symbol, String tag, BigDecimal lastAmount, String hash) {
+        MemberCoinChargeEntity memberCoinChargeEntity = new MemberCoinChargeEntity();
+        memberCoinChargeEntity.setAddress(address);
+        memberCoinChargeEntity.setMemberId(memberId);
+        memberCoinChargeEntity.setAmount(newBalance);
+        memberCoinChargeEntity.setSymbol(symbol);
+        memberCoinChargeEntity.setTag(tag);
+        memberCoinChargeEntity.setStatus(1);
+        memberCoinChargeEntity.setLastAmount(lastAmount);
+        memberCoinChargeEntity.setHash(hash);
+        String orderNo = generateNo();
+        memberCoinChargeEntity.setOrderCode(orderNo);
+        memberCoinChargeDao.insert(memberCoinChargeEntity);
+        return orderNo;
+    }
+    private String generateNo() {
+        // 生成订单号
+        Long timestamp = System.currentTimeMillis();
+        // 随机数
+        int random = (int) (Math.random() * 10);
+        return String.valueOf(timestamp).substring(2) + random;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/ChainService.java b/src/main/java/cc/mrbird/febs/mall/chain/service/ChainService.java
new file mode 100644
index 0000000..732ec34
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/ChainService.java
@@ -0,0 +1,185 @@
+package cc.mrbird.febs.mall.chain.service;
+
+import cc.mrbird.febs.common.exception.FebsException;
+import cc.mrbird.febs.mall.chain.enums.ChainEnum;
+import cc.mrbird.febs.mall.chain.enums.EthService;
+import io.reactivex.Flowable;
+import io.reactivex.disposables.Disposable;
+import lombok.extern.slf4j.Slf4j;
+import org.web3j.crypto.Credentials;
+import org.web3j.protocol.Web3j;
+import org.web3j.protocol.core.DefaultBlockParameter;
+import org.web3j.protocol.core.DefaultBlockParameterName;
+import org.web3j.protocol.core.DefaultBlockParameterNumber;
+import org.web3j.protocol.core.methods.request.EthFilter;
+import org.web3j.protocol.http.HttpService;
+import org.web3j.protocol.websocket.WebSocketClient;
+import org.web3j.protocol.websocket.WebSocketService;
+import org.web3j.tx.gas.StaticGasProvider;
+
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author
+ * @date 2022-03-23
+ **/
+@Slf4j
+public class ChainService {
+    private final static Map<String, ContractChainService> contractMap = new HashMap<>();
+
+    static {
+        for (ChainEnum chain : ChainEnum.values()) {
+                contractMap.put(chain.name(), new EthService(chain.getUrl(), chain.getAddress(), chain.getPrivateKey(), chain.getContractAddress()));
+        }
+    }
+
+    private ChainService() {
+    }
+
+    public final static ChainService INSTANCE = new ChainService();
+
+    public static ContractChainService getInstance(String chainType) {
+        ContractChainService contract = contractMap.get(chainType);
+        if (contract == null) {
+            throw new FebsException("参数错误");
+        }
+
+        return contract;
+    }
+
+    /**
+     * 监听合约事件
+     *
+     * @param startBlock 开始区块
+     */
+    public static void contractEventListener(BigInteger startBlock, ContractEventService event, String type) {
+        contractEventListener(startBlock, null, event, type);
+    }
+
+    public static void contractEventListener(BigInteger startBlock, BigInteger endBlock, ContractEventService event, String type) {
+        ChainEnum chain = ChainEnum.getValueByName(type);
+        assert chain != null;
+
+        EthUsdtContract contract = contract(chain.getPrivateKey(), chain.getContractAddress(), chain.getUrl());
+        EthFilter filter = getFilter(startBlock, endBlock, chain.getContractAddress());
+
+        Flowable<EthUsdtContract.TransferEventResponse> eventFlowable = contract.transferEventFlowable(filter);
+        eventFlowable.subscribe(e -> {
+            event.compile(e);
+        }, error -> {
+            log.error("合约监听启动报错", error);
+        });
+    }
+
+    public static void wssContractEventListener(BigInteger startBlock, ContractEventService event, String type) {
+        WebSocketService ws = null;
+        WebSocketClient webSocketClient = null;
+        Web3j web3j = null;
+
+        try {
+            webSocketClient = new WebSocketClient(new URI("wss://bsc-mainnet.nodereal.io/ws/v1/78074065950e4915aef4f12b6f357d16"));
+            ws = new WebSocketService(webSocketClient, true);
+            ws.connect();
+            web3j = Web3j.build(ws);
+            ChainEnum chain = ChainEnum.getValueByName(type);
+            assert chain != null;
+
+            EthUsdtContract ethUsdtContract = wssContract(chain.getPrivateKey(), chain.getContractAddress(), web3j);
+            EthFilter filter = getFilter(startBlock, startBlock, chain.getContractAddress());
+
+
+            Flowable<EthUsdtContract.TransferEventResponse> eventFlowable = ethUsdtContract.transferEventFlowable(filter);
+            Disposable subscribe = eventFlowable.subscribe(event::compile, error -> {
+                log.error("币安监听异常", error);
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+
+
+    public static void wssBaseCoinEventListener(BigInteger startBlock, BaseCoinService event) {
+        WebSocketService ws = null;
+        WebSocketClient webSocketClient = null;
+        Web3j web3j = null;
+
+        try {
+            webSocketClient = new WebSocketClient(new URI("wss://bsc-mainnet.nodereal.io/ws/v1/78074065950e4915aef4f12b6f357d16"));
+            ws = new WebSocketService(webSocketClient, true);
+            ws.connect();
+            web3j = Web3j.build(ws);
+
+            Disposable subscribe = web3j.replayPastAndFutureTransactionsFlowable(new DefaultBlockParameterNumber(startBlock)).subscribe(event::compile, error ->{
+                log.error("监听链上异常", error);
+            });
+        }catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    private static EthUsdtContract contract(String privateKey, String contractAddress, String url) {
+        Credentials credentials = Credentials.create(privateKey);
+        HttpService httpService = new HttpService(url);
+//        httpService.addHeader("Authorization", "Bearer " + Base64.encode("tfc:tfc123".getBytes()));
+//        httpService.addHeader("Authorization", "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJwdWJsaWMiLCJleHAiOjE2NTk5MzcxOTAsImp0aSI6IjRiMjNkYTVjLWRlZWEtNDYzNi04YjMwLWNmMmZmMjVkM2NlYyIsImlhdCI6MTY1OTkzMzU5MCwiaXNzIjoiQW5rciIsIm5iZiI6MTY1OTkzMzU5MCwic3ViIjoiZmNiNjY0YjItOGEwNC00N2E5LTg3ZjMtNTJhMjE2ODVlMzEzIn0.YfEwvDByU2MGHywsblZpEmKMIbjv4cWYkn5CaFglXY0TSANzd2pCSbIe40yU_R9_nV6xZeE8Uk74jJOdd_QvMpFyUgo-MMNWZP6uiEaYvK_K3tlpk5yzeZq9D4ruWaq8rFKggr-iaRGzu6coRSAOFv2prWll3a7NdEbmkM-y5Y85xYD6g1N-TPIpE_Y-_-WPf3JUavk744kG8YyHhGvAmk2IL0N2xePfC6CHesdJhwvmJJXzr_53dbPwit1y5KljS0iTZz3mGTML2bq4hGaEHbQxeY2fBpZOSm8sPMz-zB9IVJQKzH5-DXlPKz01mJ9XiBJlubfHsN72RdqFD-O2Tw");
+        return EthUsdtContract.load(contractAddress,
+                Web3j.build(httpService),
+                credentials,
+                new StaticGasProvider(BigInteger.valueOf(4500000L), BigInteger.valueOf(200000L)));
+    }
+
+    private static EthUsdtContract wssContract(String privateKey, String contractAddress, Web3j web3j) {
+        Credentials credentials = Credentials.create(privateKey);
+//        httpService.addHeader("Authorization", "Bearer " + Base64.encode("tfc:tfc123".getBytes()));
+//        httpService.addHeader("Authorization", "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJwdWJsaWMiLCJleHAiOjE2NTk5MzcxOTAsImp0aSI6IjRiMjNkYTVjLWRlZWEtNDYzNi04YjMwLWNmMmZmMjVkM2NlYyIsImlhdCI6MTY1OTkzMzU5MCwiaXNzIjoiQW5rciIsIm5iZiI6MTY1OTkzMzU5MCwic3ViIjoiZmNiNjY0YjItOGEwNC00N2E5LTg3ZjMtNTJhMjE2ODVlMzEzIn0.YfEwvDByU2MGHywsblZpEmKMIbjv4cWYkn5CaFglXY0TSANzd2pCSbIe40yU_R9_nV6xZeE8Uk74jJOdd_QvMpFyUgo-MMNWZP6uiEaYvK_K3tlpk5yzeZq9D4ruWaq8rFKggr-iaRGzu6coRSAOFv2prWll3a7NdEbmkM-y5Y85xYD6g1N-TPIpE_Y-_-WPf3JUavk744kG8YyHhGvAmk2IL0N2xePfC6CHesdJhwvmJJXzr_53dbPwit1y5KljS0iTZz3mGTML2bq4hGaEHbQxeY2fBpZOSm8sPMz-zB9IVJQKzH5-DXlPKz01mJ9XiBJlubfHsN72RdqFD-O2Tw");
+        return EthUsdtContract.load(contractAddress,
+                web3j,
+                credentials,
+                new StaticGasProvider(BigInteger.valueOf(4500000L), BigInteger.valueOf(200000L)));
+    }
+
+    private static EthFilter getFilter(BigInteger startBlock, String contractAddress) {
+        return getFilter(startBlock, null, contractAddress);
+    }
+
+    private static EthFilter getFilter(BigInteger startBlock, BigInteger endBlock, String contractAddress) {
+        DefaultBlockParameter startParameterName = null;
+        DefaultBlockParameter endParameterName = null;
+        if (startBlock != null) {
+            startParameterName = new DefaultBlockParameterNumber(startBlock);
+        } else {
+            startParameterName = DefaultBlockParameterName.EARLIEST;
+        }
+
+        if (endBlock != null) {
+            endParameterName = new DefaultBlockParameterNumber(endBlock);
+        } else {
+            endParameterName = DefaultBlockParameterName.LATEST;
+        }
+
+        return new EthFilter(startParameterName, endParameterName, contractAddress);
+    }
+
+    public static void main(String[] args) {
+//        ChainEnum chain = ChainEnum.getValueByName(ChainEnum.BSC_TFC.name());
+//        assert chain != null;
+//
+//        EthUsdtContract contract = contract(chain.getPrivateKey(), chain.getContractAddress(), chain.getUrl());
+//        EthFilter filter = getFilter(new BigInteger("18097238"), chain.getContractAddress());
+//
+//        contract.transferEventFlowable(filter).subscribe(e -> {
+//            System.out.println(1);
+//        }, error -> {
+//            log.error("--->", error);
+//        });
+
+//        System.out.println(ChainService.getInstance(ChainEnum.BSC_TFC.name()).totalSupply());
+    }
+
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/ContractChainService.java b/src/main/java/cc/mrbird/febs/mall/chain/service/ContractChainService.java
new file mode 100644
index 0000000..076e23c
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/ContractChainService.java
@@ -0,0 +1,31 @@
+package cc.mrbird.febs.mall.chain.service;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public interface ContractChainService {
+
+    BigInteger balanceOfUnDecimal(String address);
+
+    BigDecimal balanceOf(String address);
+
+    BigInteger allowance(String address);
+
+    boolean isAllowance(String address);
+
+    String transfer(String address);
+
+    String transfer(String address, BigDecimal amount);
+
+    int allowanceCnt(String address);
+
+    int decimals();
+
+    BigInteger blockNumber();
+
+    BigInteger totalSupply();
+
+    BigInteger totalSupplyNFT();
+
+    String safeMintNFT(String address);
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/ContractEventService.java b/src/main/java/cc/mrbird/febs/mall/chain/service/ContractEventService.java
new file mode 100644
index 0000000..fdd40df
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/ContractEventService.java
@@ -0,0 +1,6 @@
+package cc.mrbird.febs.mall.chain.service;
+
+public interface ContractEventService {
+
+    void compile(EthUsdtContract.TransferEventResponse e);
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/EthService.java b/src/main/java/cc/mrbird/febs/mall/chain/service/EthService.java
index 5faeb20..a4f1f82 100644
--- a/src/main/java/cc/mrbird/febs/mall/chain/service/EthService.java
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/EthService.java
@@ -33,7 +33,7 @@
 /**
  * ETH类,使用Web3j 下面为使用教程
  * https://kauri.io/article/925d923e12c543da9a0a3e617be963b4/manage-an-ethereum-account-with-java-and-web3js
- * 
+ *
  * @author Administrator
  *
  */
@@ -66,7 +66,7 @@
 
 	/**
 	 * 查询ETH余额
-	 * 
+	 *
 	 * @param address
 	 * @return
 	 */
@@ -90,7 +90,7 @@
 
 	/**
 	 * 创建ETH钱包
-	 * 
+	 *
 	 * @return
 	 */
 	public static Map<String, String> createEth() {
@@ -163,9 +163,9 @@
 	}
 
 	/**
-	 * 
+	 *
 	 * 方法描述:获取代币余额
-	 * 
+	 *
 	 * @param fromAddress
 	 * @param
 	 * @param
diff --git a/src/main/java/cc/mrbird/febs/mall/chain/service/UsdtErc20UpdateService.java b/src/main/java/cc/mrbird/febs/mall/chain/service/UsdtErc20UpdateService.java
index b41ae0e..c7af807 100644
--- a/src/main/java/cc/mrbird/febs/mall/chain/service/UsdtErc20UpdateService.java
+++ b/src/main/java/cc/mrbird/febs/mall/chain/service/UsdtErc20UpdateService.java
@@ -93,7 +93,7 @@
         Credentials credentials = Credentials.create(privateKey);
         EthUsdtContract contract = EthUsdtContract.load(contractAddr, getInstance(), credentials, getStaticGasProvider());
 
-        EthFilter filter = getFilter(blockNum,null,contractAddr);
+        EthFilter filter = getFilter(blockNum,blockNum,contractAddr);
 
         Map<String,BigInteger> map = new HashMap<String,BigInteger>();
         map.put("blockNum",blockNum);
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/BlockSeriveImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/BlockSeriveImpl.java
index 32a0c24..16370ec 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/impl/BlockSeriveImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/BlockSeriveImpl.java
@@ -3,7 +3,6 @@
 import cc.mrbird.febs.common.entity.FebsResponse;
 import cc.mrbird.febs.common.utils.LoginUserUtil;
 import cc.mrbird.febs.mall.chain.service.EthService;
-import cc.mrbird.febs.mall.chain.service.Trc20Service;
 import cc.mrbird.febs.mall.entity.MallMember;
 import cc.mrbird.febs.mall.entity.MemberCoinAddressEntity;
 import cc.mrbird.febs.mall.mapper.MallMemberMapper;
diff --git a/src/test/java/cc/mrbird/febs/ProfitTest.java b/src/test/java/cc/mrbird/febs/ProfitTest.java
index b770871..31e6bb5 100644
--- a/src/test/java/cc/mrbird/febs/ProfitTest.java
+++ b/src/test/java/cc/mrbird/febs/ProfitTest.java
@@ -6,6 +6,11 @@
 import cc.mrbird.febs.common.utils.AppContants;
 import cc.mrbird.febs.common.utils.LoginUserUtil;
 import cc.mrbird.febs.common.utils.MallUtils;
+import cc.mrbird.febs.common.utils.RedisUtils;
+import cc.mrbird.febs.mall.chain.enums.ChainEnum;
+import cc.mrbird.febs.mall.chain.service.BaseCoinService;
+import cc.mrbird.febs.mall.chain.service.ChainService;
+import cc.mrbird.febs.mall.chain.service.ContractEventService;
 import cc.mrbird.febs.mall.chain.service.UsdtErc20UpdateService;
 import cc.mrbird.febs.mall.entity.*;
 import cc.mrbird.febs.mall.mapper.*;
@@ -29,6 +34,7 @@
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
 import java.util.*;
@@ -414,12 +420,29 @@
 //
 
 
+    @Autowired
+    private ContractEventService bscUsdtContractEvent;
 
+
+    @Autowired
+    private BaseCoinService baseCoinService;
+    @Autowired
+    private RedisUtils redisUtils;
     @Resource
     private UsdtErc20UpdateService usdtErc20UpdateService;
     @Test
     public void scorePool(){
-        usdtErc20UpdateService.updateUsdt();
+        long start = System.currentTimeMillis();
+        Object incrementObj = redisUtils.get(AppContants.REDIS_KEY_BLOCK_ETH_INCREMENT_NUM);
+        BigInteger newest = ChainService.getInstance(ChainEnum.BSC_USDT.name()).blockNumber();
+        BigInteger block;
+        if (incrementObj == null) {
+            block = newest;
+        } else {
+            block = (BigInteger) incrementObj;
+        }
+//        ChainService.wssBaseCoinEventListener(BigInteger.valueOf(24317595), baseCoinService);
+        ChainService.wssContractEventListener(BigInteger.valueOf(24317595), bscUsdtContractEvent, ChainEnum.BSC_USDT.name());
     }
 //
 //    @Test

--
Gitblit v1.9.1