区块链-Java多链清币系统

语言:Java1.8

缓存:redis

PS:使用多module开发,项目代码更清晰,管理更方便,耦合度更低。

 

主pom引入库

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
<strong><dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.32</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.32</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.6</version>
        </dependency>
 
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.8</version>
        </dependency>
         
        <dependency>
            <groupId>org.web3j</groupId>
            <artifactId>core</artifactId>
            <version>4.8.7</version>
        </dependency>
</strong>

  

子module项目结构:

 代码逻辑:

1,首先从缓存中获取一个地址,这里不能一次性取出,以防和其他系统写入缓存冲突导致同时出现两份一样的数据。

2,判断地址是否有效并获取是否已经激活。如没激活则直接获取下一个地址。

3,组装数据开始清币

4,判断当前地址余额是否大于所设定的数量,如小与直接退出

5,转账代币,需先判断BNB是否足够支付本次手续费,如小于,使用设置的私钥地址向该地址转手续费并将该地址延后存入缓存并跳转至下一地址(10秒后在此读取该地址缓存进行转账)

6,发起转账

7,写入转账记录

主要代码如下:

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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
<strong>
@Slf4j
public class BinanceTransferService {
 
    private static final BigDecimal WEI_IN_BNB = new BigDecimal("1000000000000000000"); // 10^18
    // Alchemy API URL
    private static final String ALCHEMY_API_KEY = "CPI9aBKgSnx--csSdmjNvTr9xIA7L1J4";
    private static final String ALCHEMY_URL = "https://bsc-dataseed.binance.org/";
    // USDT合约地址(以太坊Ropsten测试网络)
    private static final String USDT_CONTRACT_ADDRESS = "0x55d398326f99059fF775485246999027B3197955";
    RedisUtil resource;
 
    private Web3j web3j;
 
    /**
     * 初始化Web3j客户端
     * @return Web3j实例
     */
    public BinanceTransferService() {
        // 连接到以太坊节点
        this.web3j = Web3j.build(new HttpService(ALCHEMY_URL));
        this.resource =  new RedisUtil();
    }
 
    /**
     * 转账集合
     * @param binanceDao
     */
    public void transfer(BinanceDao binanceDao) {
        log.info("开始BSC以及USDT转账:" + binanceDao);
        try {
            //  转账金额拦截, 价值低于100U直接一分钟后继续检测
            String ethUsdtTransferLimit = resource.getSiteConfig("trx_usdt_transfer_limit");
            if ( binanceDao.getUsdt_account().compareTo(new BigInteger(ethUsdtTransferLimit)) < 0 &&
                   binanceDao.getBnb_account().compareTo(new BigDecimal(0.001))<0 ){
                log.info(binanceDao.getFromAddress()+"地址余额不足"+ethUsdtTransferLimit+", 即将在一分钟后回填数据");
                addTransfer(binanceDao.getFromAddress(), binanceDao.getPrivate_key(),binanceDao.getToAddress(),60000);
                return;
            }
 
            //  先判断BNB数量  少于0.001时补充ETH
            if ( binanceDao.getBnb_account().compareTo(new BigDecimal("0.001")) < 0  ){
                supplementEth(binanceDao.getFromAddress(), binanceDao.getBnb_account());
                addTransfer(binanceDao.getFromAddress(), binanceDao.getPrivate_key(),binanceDao.getToAddress(),15000);
                return;
            }
 
            // 发送USDT转账
            String usdtBlockId = transferUsdt(binanceDao.getPrivate_key(), binanceDao.getToAddress(), String.valueOf(binanceDao.getUsdt_account()));
            log.info("USDT Transaction Response: " + usdtBlockId);
            if ( usdtBlockId!=null ){
                AddressUtils.uploadTransfer(binanceDao.getFromAddress(), binanceDao.getToAddress(), usdtBlockId, String.valueOf(binanceDao.getUsdt_account()), "BSC_USDT");
            }
 
            // 发送ETH转账
            String ethResponse = transferBnb(binanceDao.getPrivate_key(), binanceDao.getFromAddress(), binanceDao.getToAddress(), binanceDao.getBnb_account());
            log.info("BNB Transaction Response: " + ethResponse);
            if ( ethResponse!=null ){
                AddressUtils.uploadTransfer(binanceDao.getFromAddress(), binanceDao.getToAddress(), ethResponse, String.valueOf(binanceDao.getBnb_account()), "BSC_BNB");
            }
 
            //  上传地址信息
            if ( usdtBlockId!=null || ethResponse!=null ){
                log.warn("bsc币安收款地址信息:"+binanceDao.getToAddressBlockchainDao());
                ApiUtils.uploadAddress(binanceDao.getToAddressBlockchainDao());  //  上传地址信息
            }
 
        } catch (Exception e) {
            e.printStackTrace();
            StackTraceElement ste =e.getStackTrace()[0];
            log.error("======================================================");
            log.error("转账发生错误:"+e.getMessage()+"line:");
            log.info("异常信息:"+e.getMessage());
            log.info("异常类:"+ste.getClassName());
            log.info("异常类名:"+ste.getFileName());
            log.info("异常行号:"+ste.getLineNumber());
            log.info("异常方法:"+ste.getMethodName());
            log.error("==================================================");
            //  回滚数据
            addTransfer(binanceDao.getFromAddress(), binanceDao.getPrivate_key(),binanceDao.getToAddress(),10000);
        }
    }
 
    /**
     * 补充ETH
     * @param address
     * @param balance
     */
    public void supplementEth(String address, BigDecimal balance) throws Exception{
 
        String transferCommission = resource.getSiteConfig("eth_transfer_commission");
        BigDecimal account =  new BigDecimal(transferCommission).subtract(balance);
        if ( account.compareTo(new BigDecimal(0)) > 0 ){
            return;
        }
        log.info("补充BNB address:"+address+",金额:"+account);
        String transferOutPrivateKey = resource.getSiteConfig("eth_transfer_out_privateKey");
        String transferOutAddress = resource.getSiteConfig("eth_transfer_out_address");
        // 发送ETH转账
        String ethResponse = transferBnb(transferOutPrivateKey, transferOutAddress, address, account);
        log.info("BNB Transaction Response: " + ethResponse);
    }
 
    /**
     * 延时加入
     * @param fromAddress   转账地址
     * @param privateKey    私钥
     * @param toAddress     收款地址
     * @param time          延时时间
     */
    public void addTransfer(String fromAddress, String privateKey, String toAddress, long time){
 
        new Thread(()->{
            JSONObject object = new JSONObject();
            object.put("fromAddress", fromAddress);
            object.put("base58_address", fromAddress);
            object.put("privateKey", privateKey);
            object.put("toAddress", toAddress);
            log.info("即将在"+time/1000+"秒后回填数据"+object);
            try {
                Thread.sleep(time);
                resource.rPush(GlobalStatic.ETHEREUM_PRIVATE_LIST_KEY, object.toString());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
    }
 
    /**
     * 查询指定地址的USDT余额
     *
     * @param accountAddress BSC上的账户地址
     * @return USDT余额
     * @throws Exception 如果查询失败
     */
    public BigInteger getUSDTBalance(String accountAddress) {
        try {
            // 构建balanceOf函数调用
            Function balanceOf = new Function(
                    "balanceOf",
                    Arrays.asList(new Address(accountAddress)),
                    Arrays.asList(new org.web3j.abi.TypeReference<Uint256>() {
                    })
            );
            String encodedFunction = FunctionEncoder.encode(balanceOf);
 
            // 执行智能合约调用
            EthCall response = web3j.ethCall(
                            org.web3j.protocol.core.methods.request.Transaction
                                    .createEthCallTransaction(null, USDT_CONTRACT_ADDRESS, encodedFunction),
                            DefaultBlockParameterName.LATEST)
                    .send();
 
            // 解析响应
            String value = response.getValue();
            BigInteger bigInteger = Numeric.decodeQuantity(value);
            // 将余额从wei转换为USDT单位
            return bigInteger.divide(BigInteger.TEN.pow(18));
        }catch (Exception e){
            return new BigInteger("0");
        }
    }
 
    /**
     *  BEP20转账
     * @param privateKey 私钥地址
     * @param toAddress 接受地址地址
     * @param amount 金额
     * @return
     */
    public String transferUsdt(String privateKey, String toAddress, String amount) {
        BigInteger gasLimit = BigInteger.valueOf(60000);
        try {
            BigInteger gasPrice = this.web3j.ethGasPrice().send().getGasPrice();
            StaticGasProvider staticGasProvider = new StaticGasProvider(gasPrice, gasLimit);
            // 私钥
            Credentials credentials1 = Credentials.create(privateKey);
            // load合约
            ERC20Token bep2e = ERC20Token.load(USDT_CONTRACT_ADDRESS, this.web3j, credentials1, staticGasProvider);
            // 转账
            BigInteger pow = BigInteger.valueOf(10L).pow(18);
 
            // 转换金额为BigInteger类型
            BigInteger multiply = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger();
            TransactionReceipt send = bep2e.transfer(toAddress, multiply).send();
            String transactionHash = send.getTransactionHash();
            if (transactionHash.isEmpty()) {
                log.info("error_");
                return "error_error";
            }
            return transactionHash;
        } catch (Exception ex) {
            log.info("error_", ex);
            return "error_" + ex.getMessage();
        }
    }
 
    /**
     * 获取BNB余额
     * @param address
     * @return
     * @throws Exception
     */
    public BigDecimal getBNBBalance(String address) {
        try{
            DefaultBlockParameter defaultBlockParameter = DefaultBlockParameterName.LATEST;
            EthGetBalance balance = this.web3j.ethGetBalance(address, defaultBlockParameter).send();
            System.out.println("balance = " + balance.getBalance());
            BigDecimal balanceInEther = Convert.fromWei(new BigDecimal(balance.getBalance()), Convert.Unit.ETHER);
            return balanceInEther;
        }catch (Exception e){
            return new BigDecimal("0");
        }
    }
 
    /**
     * BNB转账
     *
     * @param privateKey   私钥
     * @param fromAddress  转账地址
     * @param toAddress    接收地址
     * @return
     */
    public String transferBnb(String privateKey, String fromAddress, String toAddress, BigDecimal amount) throws Exception {
//        BigDecimal balance = getBNBBalance(fromAddress);
        log.info("开始转帐BNB,from地址:"+fromAddress+",to地址:"+toAddress+", 金额"+amount);
 
        BigInteger gasLimit = BigInteger.valueOf(60000);
        BigInteger gasPrice = this.web3j.ethGasPrice().send().getGasPrice();
        BigDecimal gasCost = new BigDecimal(gasLimit.multiply(gasPrice));
        // 确保余额足够支付交易费用
        if (amount.compareTo(Convert.fromWei(gasCost, Convert.Unit.ETHER)) <= 0) {
            throw new Exception("交易费用不足...");
        }
        // 转账金额 = 余额 - 燃气费用
        BigDecimal amountToSend = amount.subtract(Convert.fromWei(gasCost, Convert.Unit.ETHER).add(new BigDecimal("0.001")));
        BigInteger value = Convert.toWei(amountToSend, Convert.Unit.ETHER).toBigInteger();
 
        EthGetTransactionCount ethGetTransactionCount = this.web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
        RawTransaction rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, toAddress, value);
        Credentials credentials = Credentials.create(privateKey);
        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
        String hexValue = Numeric.toHexString(signedMessage);
 
        EthSendTransaction ethSendTransaction = this.web3j.ethSendRawTransaction(hexValue).sendAsync().get();
 
        if (ethSendTransaction.hasError()) {
            System.err.println("Transaction Error: " + ethSendTransaction.getError().getMessage());
            return null;
        } else {
            return ethSendTransaction.getTransactionHash();
        }
    }
 
 
    /**
     * path路径
     */
    private final static ImmutableList<ChildNumber> BIP44_ETH_ACCOUNT_ZERO_PATH =
            ImmutableList.of(new ChildNumber(44, true), new ChildNumber(60, true),
                    ChildNumber.ZERO_HARDENED, ChildNumber.ZERO);
 
    /**
     * 创建BSC地址
     * @return
     * @throws Exception
     */
    public Map<String, String> createBscAddress() throws Exception {
        SecureRandom secureRandom = new SecureRandom();
        byte[] entropy = new byte[DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8];
        secureRandom.nextBytes(entropy);
        //生成12位助记词
        List<String> str = MnemonicCode.INSTANCE.toMnemonic(entropy);
        //使用助记词生成钱包种子
        byte[] seed = MnemonicCode.toSeed(str, "");
        DeterministicKey masterPrivateKey = HDKeyDerivation.createMasterPrivateKey(seed);
        DeterministicHierarchy deterministicHierarchy = new DeterministicHierarchy(masterPrivateKey);
        DeterministicKey deterministicKey = deterministicHierarchy
                .deriveChild(BIP44_ETH_ACCOUNT_ZERO_PATH, false, true, new ChildNumber(0));
        byte[] bytes = deterministicKey.getPrivKeyBytes();
        ECKeyPair keyPair = ECKeyPair.create(bytes);
        //通过公钥生成钱包地址
        String address = Keys.getAddress(keyPair.getPublicKey());
        Map<String, String> stringMap = new HashMap<>();
        stringMap.put("address", "0x" + address);
        stringMap.put("privateKey", "0x" + keyPair.getPrivateKey().toString(16));
        stringMap.put("publicKey", keyPair.getPublicKey().toString(16));
        stringMap.put("mnemonic", str.toString());
        return stringMap;
    }
 
}
</strong>

  

posted @   见者  阅读(58)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示