上一节我们主要是环境搭建,主要是为了能够快速得去开发,有些地方只是简单的介绍,比如ETH 、web3j等等这些。
这一节我们来用代码来实现BNB转账、BEP20转账、链上交易监控
话不多说,我们直接用代码实现吧
- BNB转账
java
/**
* BNB转账
* @param toAddress 接收地址地址
* @param amount 金额
* @return
*/
@Override
public String transBscBnbJson(String toAddress, String amount) throws Exception {
Web3j web3j = Web3j.build(new HttpService(tronServiceConfig.getBscUrl()));
EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(tronServiceConfig.getBscFromAddress(), DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
BigInteger gasLimit = BigInteger.valueOf(60000);
BigInteger functionAmount = Convert.toWei(new BigDecimal(amount), Convert.Unit.ETHER).toBigInteger();
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, toAddress, functionAmount);
// 私钥
Credentials credentials = Credentials.create(tronServiceConfig.getBscFromPrivateKey());
//进行签名操作
byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
String hexValues = Numeric.toHexString(signMessage);
//发起交易
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValues).sendAsync().get();
String hash = ethSendTransaction.getTransactionHash();
if (hash != null) {
//执行业务
log.info("BNB转账执行成功:" + hash);
}
return hash;
}
- BEP20转账
java
/**
* BEP20转账
* @param toAddress 接受地址地址
* @param amount 金额
* @return
*/
@Override
public String transBscJson(String toAddress, String amount) {
BigInteger gasLimit = BigInteger.valueOf(60000);
try {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
StaticGasProvider staticGasProvider = new StaticGasProvider(gasPrice, gasLimit);
// 私钥
Credentials credentials1 = Credentials.create(MarketConstruct.BOCT_STAKE_CONTRACT_OWER_PRIVATE_KEY);
// load合约
BEP2E bep2e = BEP2E.load(MarketConstruct.BOCT_CONTRACT_ADDRESS, web3j, credentials1, staticGasProvider);
// 转账
BigInteger pow = BigInteger.valueOf(10L).pow(18);
BigInteger multiply = new BigDecimal(amount).multiply(new BigDecimal(pow.toString())).toBigInteger();
TransactionReceipt send = bep2e.transfer(toAddress, multiply).send();
String transactionHash = send.getTransactionHash();
if (StrUtil.isEmpty(transactionHash)) {
log.info("error_");
return "error_error";
}
return transactionHash;
} catch (Exception ex) {
log.info("error_", ex);
return "error_" + ex.getMessage();
}
}
当我们转账成功后,需要进行账户余额查询
BNB与BEP20余额查询
java
/**
* <b>功能描述:</b>查询BNB余额<br>
* <b>修订记录:</b><br>
*/
public BigDecimal queryBNBBalance(String address) throws Exception {
DefaultBlockParameter defaultBlockParameter = new DefaultBlockParameterNumber(web3b.ethBlockNumber().send().getBlockNumber());
EthGetBalance balance = web3b.ethGetBalance(address, defaultBlockParameter).send();
BigDecimal bigDecimal = new BigDecimal(balance.getBalance());
BigInteger pow = BigInteger.valueOf(10L).pow(18);
return bigDecimal.divide(new BigDecimal(pow), 4, RoundingMode.HALF_UP);
}
/**
* <b>功能描述:</b>查询BEP20余额<br>
* <b>修订记录:</b><br>
* <li>20240309 | | 创建方法</li><br>
*/
public BigDecimal queryBEP2EBBalance(String contractAddr, String address) throws Exception {
try {
BigInteger gasPrice = web3b.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new ReadonlyTransactionManager(web3b, address);
StaticGasProvider staticGasProvider = new StaticGasProvider(gasPrice, BigInteger.valueOf(4700000));
BEP2E bep2e = BEP2E.load(contractAddr, web3b, transactionManager, staticGasProvider);
BigInteger balance = bep2e.balanceOf(address).send();
BigDecimal bigDecimal = new BigDecimal(balance);
BigInteger pow = BigInteger.valueOf(10L).pow(18);
return bigDecimal.divide(new BigDecimal(pow), 4, RoundingMode.HALF_UP);
} catch (Exception ex) {
return BigDecimal.ZERO;
}
}
3.链上交易监控
和之前TRON TRC20同样的艰辛,BNB的监控逻辑和业务包括web3j的支持,以及RPC接口的稳定性,简直是折腾了一个够。
最终的最好的解决办法:自建一个区块链节点,可惜本人没有那么大的财力,去长期购买大容量的服务器支持,只能做了一个服务接口,服务不稳定时,自动重启连接。效果还过得去吧。目前为止,没有丢块现象了。
假如是自建区块链节点,又不是JAVA语言开发,那就不会出现问题
废话不多说,首先还是查找链上最大的交易块。
java
Request<?, EthBlockNumber> request = web3j.ethBlockNumber();
BigInteger blockNumber = request.send().getBlockNumber();
java
/**
* <b>功能描述:</b>创建开始与结束区块, 重放这段时间内的交易,防止遗漏<br>
* <b>修订记录:</b><br>
*/
public void startReplayListen_BiAn(Web3j web3j, BigInteger startBlockNum) {
//创建开始与结束区块, 重放这段时间内的交易,防止遗漏
DefaultBlockParameter startBlock = new DefaultBlockParameterNumber(startBlockNum);
web3j.replayPastTransactionsFlowable(startBlock, DefaultBlockParameterName.LATEST).subscribe(tx -> {
String fromAddress = tx.getFrom();
String toAddress = tx.getTo();
// 发现了指定地址上的交易
BigInteger blockNumber = tx.getBlockNumber();
KeyValue keyValueNum = keyValueMapper.selectByKey(MarketConstruct.BOCT_STAKE_CONTRACT_ADDRESS);
if (keyValueNum.getValue().equalsIgnoreCase(toAddress)) {
String transactionHash = tx.getHash();
String timestamp = "";
try {
DefaultBlockParameter defaultBlockParameter = DefaultBlockParameter.valueOf(blockNumber);
EthBlock ethBlock = web3j.ethGetBlockByNumber(defaultBlockParameter, false).send();
timestamp = String.valueOf(ethBlock.getBlock().getTimestamp());
Long timestamp1 = Long.parseLong(timestamp) * 1000L;
BigDecimal amount = new BigDecimal(new BigInteger(tx.getInput().substring(12), 16)).divide(BigDecimal.valueOf(1000000000000000000.0), 18, BigDecimal.ROUND_HALF_EVEN);
checkBlock(transactionHash, tx.getBlockNumber(), fromAddress, amount, timestamp1.toString(), 1L, BigInteger.valueOf(1L), BigInteger.valueOf(1L));
} catch (IOException e) {
log.error("Block timestamp get failure,block number is {}", blockNumber);
log.error("Block timestamp get failure,{}", e.getMessage());
}
}
}, error -> log.error(" ### replayPastTransactionsFlowable error= ", error));
}
全网的监控代码基本清一色的是下方代码方法:
java
web3j.ethLogFlowable(ethFilter).subscribe(logs -> {
// ......
}, error -> log.error("contractExtract subscribe in error", error));
可惜运行大概一个小时之后,就无法正常使用,web3j内部错误,github上寻求了各种方法,包括改web3j版本,将web3j的监控改为websocket都无法完美实现,也是通过研究和大量的调试,才找到了最好办法。
假如有大神可完美,那就不吝赐教000
目前市面上Java开发虽然也是主流,但是可以使用其他开发语言实现区块链功能,那就改变下,比如Go。
本人只是为了业务代码工程只停留在Java一个项目内才死脑筋JAVA开发的,其实还是还做了一套Go的监控代码,那用起来是非常舒心。