|
@@ -3,8 +3,6 @@ package com.table.transfer.module.service;
|
|
|
|
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
import cn.hutool.json.JSONUtil;
|
|
|
-import com.google.common.cache.Cache;
|
|
|
|
|
-import com.google.common.cache.CacheBuilder;
|
|
|
|
|
import com.table.transfer.module.enpty.ChainCoinDetail;
|
|
import com.table.transfer.module.enpty.ChainCoinDetail;
|
|
|
import com.table.transfer.module.enpty.TransactionInfoDTO;
|
|
import com.table.transfer.module.enpty.TransactionInfoDTO;
|
|
|
import com.table.transfer.module.enpty.TransferRequest;
|
|
import com.table.transfer.module.enpty.TransferRequest;
|
|
@@ -12,6 +10,7 @@ import com.table.transfer.module.enpty.TransferResponse;
|
|
|
import com.table.transfer.util.CryptoUtil;
|
|
import com.table.transfer.util.CryptoUtil;
|
|
|
import com.table.transfer.util.aUtil;
|
|
import com.table.transfer.util.aUtil;
|
|
|
import com.table.transfer.util.ether.ChainCoinDetailManager;
|
|
import com.table.transfer.util.ether.ChainCoinDetailManager;
|
|
|
|
|
+import com.table.transfer.util.ether.EtherNonceManager;
|
|
|
import com.table.transfer.util.ether.Web3jManager;
|
|
import com.table.transfer.util.ether.Web3jManager;
|
|
|
import com.table.transfer.util.encryp.RSAEncryptionUtil;
|
|
import com.table.transfer.util.encryp.RSAEncryptionUtil;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
@@ -40,12 +39,10 @@ import java.math.BigInteger;
|
|
|
import java.math.RoundingMode;
|
|
import java.math.RoundingMode;
|
|
|
import java.rmi.ServerException;
|
|
import java.rmi.ServerException;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
-import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
-import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
@Service
|
|
@Service
|
|
|
-public class EthereumService implements BlockchainService {
|
|
|
|
|
|
|
+public class EthereumService {
|
|
|
|
|
|
|
|
//EVM 链上的 ERC20 固定的事件签名keccak256 哈希
|
|
//EVM 链上的 ERC20 固定的事件签名keccak256 哈希
|
|
|
String TRANSFER_EVENT_SIGNATURE = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
String TRANSFER_EVENT_SIGNATURE = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
@@ -53,14 +50,6 @@ public class EthereumService implements BlockchainService {
|
|
|
// 默认 Gas Limit(保险值)
|
|
// 默认 Gas Limit(保险值)
|
|
|
public static final BigInteger DEFAULT_GAS_LIMIT_NATIVE = BigInteger.valueOf(21_000);
|
|
public static final BigInteger DEFAULT_GAS_LIMIT_NATIVE = BigInteger.valueOf(21_000);
|
|
|
public static final BigInteger DEFAULT_GAS_LIMIT_TOKEN = BigInteger.valueOf(120_000);
|
|
public static final BigInteger DEFAULT_GAS_LIMIT_TOKEN = BigInteger.valueOf(120_000);
|
|
|
- // BSC:官方显示平均手续费,后续应该在数据库中配置,2021年时出现过手续费暴涨的情况,手动配置可以提高最低值,提高成功率
|
|
|
|
|
-
|
|
|
|
|
- // 全局 nonce 锁,到期自动释放
|
|
|
|
|
- private final Cache<String, Object> nonceLocks = CacheBuilder.newBuilder()
|
|
|
|
|
- .expireAfterAccess(1, TimeUnit.HOURS) // 1小时无访问自动移除
|
|
|
|
|
- .build();
|
|
|
|
|
- private final Map<String, Object> pendingTransfers = new ConcurrentHashMap<>();
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取当前网络 gas price,并设置“最低安全值”
|
|
* 获取当前网络 gas price,并设置“最低安全值”
|
|
@@ -80,13 +69,11 @@ public class EthereumService implements BlockchainService {
|
|
|
|
|
|
|
|
BigInteger maxGasPrice = chainCoinDetail.getMaxGasPrice();
|
|
BigInteger maxGasPrice = chainCoinDetail.getMaxGasPrice();
|
|
|
if (networkGasPrice.compareTo(maxGasPrice) > 0) {
|
|
if (networkGasPrice.compareTo(maxGasPrice) > 0) {
|
|
|
- throw new ServerException("手续费超过设定最大值,当前估算Price"+networkGasPrice);
|
|
|
|
|
|
|
+ throw new ServerException(StrUtil.format("手续费超过设定最大值:{},当前估算Price:{}", maxGasPrice, networkGasPrice));
|
|
|
}
|
|
}
|
|
|
return networkGasPrice;
|
|
return networkGasPrice;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
public void validateTransferRequest(TransferRequest transferRequest) throws Exception {
|
|
public void validateTransferRequest(TransferRequest transferRequest) throws Exception {
|
|
|
String pk = RSAEncryptionUtil.decrypt(transferRequest.getEncryptionPrivateKey());
|
|
String pk = RSAEncryptionUtil.decrypt(transferRequest.getEncryptionPrivateKey());
|
|
|
Credentials credentials = Credentials.create(pk);
|
|
Credentials credentials = Credentials.create(pk);
|
|
@@ -107,13 +94,13 @@ public class EthereumService implements BlockchainService {
|
|
|
if (ChainCoinDetailManager.getChainCoinDetail(transferRequest.getAssetCode()) == null) {
|
|
if (ChainCoinDetailManager.getChainCoinDetail(transferRequest.getAssetCode()) == null) {
|
|
|
throw new Exception("不支持" + transferRequest.getAssetCode());
|
|
throw new Exception("不支持" + transferRequest.getAssetCode());
|
|
|
}
|
|
}
|
|
|
- //todo 支持的类型校验 合约
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
- @Override
|
|
|
|
|
public TransferResponse transfer(TransferRequest transferRequest) throws Exception {
|
|
public TransferResponse transfer(TransferRequest transferRequest) throws Exception {
|
|
|
validateTransferRequest(transferRequest);
|
|
validateTransferRequest(transferRequest);
|
|
|
|
|
+ //链
|
|
|
|
|
+ String chain = transferRequest.getChain();
|
|
|
//交易对
|
|
//交易对
|
|
|
String assetCode = transferRequest.getAssetCode();
|
|
String assetCode = transferRequest.getAssetCode();
|
|
|
//接受地址
|
|
//接受地址
|
|
@@ -134,159 +121,100 @@ public class EthereumService implements BlockchainService {
|
|
|
ChainCoinDetail chainCoinDetail = ChainCoinDetailManager.getChainCoinDetail(assetCode);
|
|
ChainCoinDetail chainCoinDetail = ChainCoinDetailManager.getChainCoinDetail(assetCode);
|
|
|
|
|
|
|
|
Credentials credentials = Credentials.create(privateKey);
|
|
Credentials credentials = Credentials.create(privateKey);
|
|
|
- //重试次数
|
|
|
|
|
- int retryCount = 0;
|
|
|
|
|
//hash
|
|
//hash
|
|
|
- String sentTxHash = null;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ String sentTxHash;
|
|
|
|
|
+ //nonce
|
|
|
|
|
+ BigInteger nonce = BigInteger.ZERO;
|
|
|
try {
|
|
try {
|
|
|
- //todo chainId和链检查 必须相同,避免跨链丢币风险。
|
|
|
|
|
-
|
|
|
|
|
//4. 转换金额为wei
|
|
//4. 转换金额为wei
|
|
|
BigInteger decimalsAmount = toWei(transferRequest.getAmount(), chainCoinDetail.getDecimal());
|
|
BigInteger decimalsAmount = toWei(transferRequest.getAmount(), chainCoinDetail.getDecimal());
|
|
|
if (decimalsAmount.compareTo(BigInteger.ONE) < 0) {
|
|
if (decimalsAmount.compareTo(BigInteger.ONE) < 0) {
|
|
|
return TransferResponse.error("转账金额过低");
|
|
return TransferResponse.error("转账金额过低");
|
|
|
}
|
|
}
|
|
|
- //2.上锁获取nonce
|
|
|
|
|
- BigInteger nonce = null;
|
|
|
|
|
- if (pendingTransfers.containsKey(fromAddress)) {
|
|
|
|
|
- throw new Exception("该发送地址已有未完成转账");
|
|
|
|
|
- }
|
|
|
|
|
- pendingTransfers.put(fromAddress, true);
|
|
|
|
|
-
|
|
|
|
|
- Object lock = nonceLocks.get(fromAddress, Object::new);
|
|
|
|
|
- nonce = getNonce(assetCode, fromAddress);
|
|
|
|
|
- while (retryCount < 3) {
|
|
|
|
|
- try {
|
|
|
|
|
-
|
|
|
|
|
- synchronized (lock) {
|
|
|
|
|
- log.info("【转账开始】账户={},目标={}, 金额={}, nonce={}", fromAddress, toAddress, amount, nonce);
|
|
|
|
|
- //5. 构建交易
|
|
|
|
|
- RawTransaction rawTransaction;
|
|
|
|
|
- //3.估算gas和gaslimit 估算个屁,limit和price估算完全不靠谱
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //5. 构建交易
|
|
|
|
|
+ RawTransaction rawTransaction;
|
|
|
|
|
+ //3.估算gas和gaslimit 估算个屁,limit和price估算完全不靠谱
|
|
|
// BigInteger gasLimit = estimateGasSafely(transferRequest);
|
|
// BigInteger gasLimit = estimateGasSafely(transferRequest);
|
|
|
- BigInteger gasLimit= isTokenTransfer ? DEFAULT_GAS_LIMIT_TOKEN : DEFAULT_GAS_LIMIT_NATIVE;
|
|
|
|
|
- BigInteger currentGasPrice = getSafeGasPrice(transferRequest);
|
|
|
|
|
- log.info("gasLimit: {},currentGasPrice {}", gasLimit, currentGasPrice);
|
|
|
|
|
- //代币转账
|
|
|
|
|
- if (isTokenTransfer) {
|
|
|
|
|
- // 构造代币转账的 function 调用
|
|
|
|
|
- Function function = new Function(
|
|
|
|
|
- "transfer",
|
|
|
|
|
- Arrays.asList(new Address(toAddress), new Uint256(decimalsAmount)),
|
|
|
|
|
- Arrays.asList(new TypeReference<Bool>() {
|
|
|
|
|
- })
|
|
|
|
|
- );
|
|
|
|
|
- String data = FunctionEncoder.encode(function);
|
|
|
|
|
-
|
|
|
|
|
- log.info("【代币转账开始】发送者={}, 接收者={}, 代币合约={}, 金额={}, nonce={}", fromAddress, toAddress, contractAddress, decimalsAmount, nonce);
|
|
|
|
|
- // 构造 RawTransaction:目标是代币合约地址
|
|
|
|
|
- rawTransaction = RawTransaction.createTransaction(
|
|
|
|
|
- nonce,
|
|
|
|
|
- currentGasPrice,
|
|
|
|
|
- gasLimit,
|
|
|
|
|
- transferRequest.getContractAddress(),
|
|
|
|
|
- BigInteger.ZERO,
|
|
|
|
|
- data
|
|
|
|
|
- );
|
|
|
|
|
- } else {
|
|
|
|
|
- //主币转账
|
|
|
|
|
- log.info("【转账开始】账户={},目标={}, 金额={}, nonce={}", fromAddress, toAddress, amount, nonce);
|
|
|
|
|
- rawTransaction = RawTransaction.createEtherTransaction(
|
|
|
|
|
- nonce,
|
|
|
|
|
- currentGasPrice,
|
|
|
|
|
- gasLimit,
|
|
|
|
|
- toAddress,
|
|
|
|
|
- decimalsAmount
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //6.签名交易
|
|
|
|
|
- byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, chainCoinDetail.getChainId(), credentials);
|
|
|
|
|
- String hexValue = Numeric.toHexString(signedMessage);
|
|
|
|
|
- //7.发送交易
|
|
|
|
|
- EthSendTransaction response = web3j.ethSendRawTransaction(hexValue).send();
|
|
|
|
|
-
|
|
|
|
|
- if (response.hasError()) {
|
|
|
|
|
- String errorMsg = response.getError().getMessage();
|
|
|
|
|
- // 仅对 underpriced 错误重试(同一 nonce)
|
|
|
|
|
- if (errorMsg.contains("underpriced") || errorMsg.contains("replacement transaction underpriced")) {
|
|
|
|
|
- retryCount++;
|
|
|
|
|
- log.warn(" 交易因手续费太低被拒,nonce={},第 {}/3 次重试,gasPrice={}",
|
|
|
|
|
- nonce, retryCount, currentGasPrice);
|
|
|
|
|
-
|
|
|
|
|
- // 根据重试次数动态提高 gasPrice
|
|
|
|
|
- currentGasPrice = currentGasPrice.multiply(BigInteger.valueOf(12)).divide(BigInteger.valueOf(10)); // +20%
|
|
|
|
|
-
|
|
|
|
|
- // 不超过链上限
|
|
|
|
|
- if (currentGasPrice.compareTo(chainCoinDetail.getMaxGasPrice()) > 0) {
|
|
|
|
|
- //todo 超过了链的上限,直接抛弃,然后修改数据库错误提示,告知是因为手续费太高导致的,避免大额手续费浪费
|
|
|
|
|
- // 更新数据库
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- continue; // 重试(同一 nonce)
|
|
|
|
|
- } else {
|
|
|
|
|
- // 其他错误直接抛出,如 nonce too low, insufficient funds, already known
|
|
|
|
|
- log.error("节点拒绝交易(不可重试): {}", errorMsg);
|
|
|
|
|
- throw new Exception("交易失败: " + errorMsg);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 8.成功发送,拿到哈希
|
|
|
|
|
- sentTxHash = response.getTransactionHash();
|
|
|
|
|
- }
|
|
|
|
|
- log.info("交易已广播,TxHash={}", sentTxHash);
|
|
|
|
|
- // 不再重试发送,直接等待确认
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- } catch (IOException e) {
|
|
|
|
|
- // 网络层异常:可能是超时,但交易可能已在链上
|
|
|
|
|
- if (sentTxHash != null) {
|
|
|
|
|
- TransactionInfoDTO transactionInfoByHash = getTransactionInfoByHash(assetCode, sentTxHash);
|
|
|
|
|
- if (transactionInfoByHash != null) {
|
|
|
|
|
- log.warn("网络异常,但交易已发送,尝试查询链上状态: {}", sentTxHash);
|
|
|
|
|
- }
|
|
|
|
|
- break; // 跳出重试,进入等待
|
|
|
|
|
- } else {
|
|
|
|
|
- // 连广播都没完成,且不是 underpriced 错误,不重试
|
|
|
|
|
- log.error("网络异常且无交易哈希,放弃重试", e);
|
|
|
|
|
- throw new Exception("网络异常,无法发送交易" + e);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("交易过程发生未预期异常", e);
|
|
|
|
|
- throw e;
|
|
|
|
|
|
|
+ BigInteger gasLimit = isTokenTransfer ? DEFAULT_GAS_LIMIT_TOKEN : DEFAULT_GAS_LIMIT_NATIVE;
|
|
|
|
|
+ BigInteger currentGasPrice = getSafeGasPrice(transferRequest);
|
|
|
|
|
+ log.info("gasLimit: {},currentGasPrice {}", gasLimit, currentGasPrice);
|
|
|
|
|
+ //代币转账
|
|
|
|
|
+ if (isTokenTransfer) {
|
|
|
|
|
+ // 构造代币转账的 function 调用
|
|
|
|
|
+ Function function = new Function(
|
|
|
|
|
+ "transfer",
|
|
|
|
|
+ Arrays.asList(new Address(toAddress), new Uint256(decimalsAmount)),
|
|
|
|
|
+ Arrays.asList(new TypeReference<Bool>() {
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+ String data = FunctionEncoder.encode(function);
|
|
|
|
|
+
|
|
|
|
|
+ nonce = EtherNonceManager.getNonce(chain, fromAddress);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("【代币转账开始】发送者={}, 接收者={}, 代币合约={}, 金额={}, nonce={}", fromAddress, toAddress, contractAddress, decimalsAmount, nonce);
|
|
|
|
|
+ // 构造 RawTransaction:目标是代币合约地址
|
|
|
|
|
+ rawTransaction = RawTransaction.createTransaction(
|
|
|
|
|
+ nonce,
|
|
|
|
|
+ currentGasPrice,
|
|
|
|
|
+ gasLimit,
|
|
|
|
|
+ transferRequest.getContractAddress(),
|
|
|
|
|
+ BigInteger.ZERO,
|
|
|
|
|
+ data
|
|
|
|
|
+ );
|
|
|
|
|
+ } else {
|
|
|
|
|
+ //主币转账
|
|
|
|
|
+ log.info("【转账开始】账户={},目标={}, 金额={}, nonce={}", fromAddress, toAddress, amount, nonce);
|
|
|
|
|
+ rawTransaction = RawTransaction.createEtherTransaction(
|
|
|
|
|
+ nonce,
|
|
|
|
|
+ currentGasPrice,
|
|
|
|
|
+ gasLimit,
|
|
|
|
|
+ toAddress,
|
|
|
|
|
+ decimalsAmount
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ //6.签名交易
|
|
|
|
|
+ byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, chainCoinDetail.getChainId(), credentials);
|
|
|
|
|
+ String hexValue = Numeric.toHexString(signedMessage);
|
|
|
|
|
+ //7.发送交易
|
|
|
|
|
+ EthSendTransaction response = web3j.ethSendRawTransaction(hexValue).send();
|
|
|
|
|
+
|
|
|
|
|
+ if (response.hasError()) {
|
|
|
|
|
+ String errorMsg = response.getError().getMessage();
|
|
|
|
|
+ // 仅对 underpriced 错误重试(同一 nonce)
|
|
|
|
|
+ if (errorMsg.contains("underpriced") || errorMsg.contains("replacement transaction underpriced")) {
|
|
|
|
|
+ log.warn(" 交易因手续费太低被拒,nonce={},gasPrice={}", nonce, currentGasPrice);
|
|
|
|
|
+ throw new Exception("交易因手续费太低被拒: " + errorMsg);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ String f = StrUtil.format("{}转账未知异常{}", chain, errorMsg);
|
|
|
|
|
+ log.error(f);
|
|
|
|
|
+ throw new Exception(f);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 8.成功发送,拿到哈希
|
|
|
|
|
+ sentTxHash = response.getTransactionHash();
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
if (sentTxHash == null) {
|
|
if (sentTxHash == null) {
|
|
|
- // 说明 3 次都失败了,且没拿到哈希
|
|
|
|
|
- log.error("交易发送失败:尝试 3 次均被拒绝(gasPrice 过低),nonce={}", nonce);
|
|
|
|
|
- // 注意:这里不能抛“可重试”异常,否则外部可能再调用
|
|
|
|
|
- throw new Exception("交易因手续费太低被拒,已尝试3次,请稍后重试");
|
|
|
|
|
|
|
+ // 没拿到哈希
|
|
|
|
|
+ log.error("交易已发送,且未提示异常,但是hash为空");
|
|
|
|
|
+ throw new Exception("交易已发送,且未提示异常,但是hash为空");
|
|
|
}
|
|
}
|
|
|
log.info("交易已发送,TxHash: {}", sentTxHash);
|
|
log.info("交易已发送,TxHash: {}", sentTxHash);
|
|
|
-
|
|
|
|
|
-// // 11. 立即验证是否进入 mempool?
|
|
|
|
|
-// if (!isTransactionInMempool(web3j, sentTxHash)) {
|
|
|
|
|
-// log.error("交易未立即进入 mempool,可能广播失败: {}", sentTxHash);
|
|
|
|
|
-// }
|
|
|
|
|
return TransferResponse.success(sentTxHash);
|
|
return TransferResponse.success(sentTxHash);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- log.error("ETH转账失败: {}", e.getMessage());
|
|
|
|
|
- return TransferResponse.error("ETH转账失败: " + e.getMessage());
|
|
|
|
|
- } finally {
|
|
|
|
|
- pendingTransfers.remove(fromAddress);
|
|
|
|
|
|
|
+ String msg = StrUtil.format("{}转账失败: {}", assetCode, e.getMessage());
|
|
|
|
|
+ log.error(msg);
|
|
|
|
|
+ return TransferResponse.error(msg);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取gasLimit
|
|
* 获取gasLimit
|
|
|
- *
|
|
|
|
|
- * @param request
|
|
|
|
|
- * @return
|
|
|
|
|
*/
|
|
*/
|
|
|
public BigInteger estimateGasSafely(TransferRequest request) {
|
|
public BigInteger estimateGasSafely(TransferRequest request) {
|
|
|
String chain = request.getChain();
|
|
String chain = request.getChain();
|
|
@@ -338,29 +266,11 @@ public class EthereumService implements BlockchainService {
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("Gas 估算准备阶段异常: {}", e.getMessage());
|
|
log.error("Gas 估算准备阶段异常: {}", e.getMessage());
|
|
|
- e.printStackTrace();
|
|
|
|
|
// 返回基于链类型的默认值
|
|
// 返回基于链类型的默认值
|
|
|
return isTokenTransfer ? DEFAULT_GAS_LIMIT_TOKEN : DEFAULT_GAS_LIMIT_NATIVE;
|
|
return isTokenTransfer ? DEFAULT_GAS_LIMIT_TOKEN : DEFAULT_GAS_LIMIT_NATIVE;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取nonce/交易总数
|
|
|
|
|
- *
|
|
|
|
|
- * @return
|
|
|
|
|
- * @throws Exception
|
|
|
|
|
- */
|
|
|
|
|
- public BigInteger getNonce(String assetCode, String address) throws Exception {
|
|
|
|
|
- Web3j web3j = Web3jManager.getWeb3j(aUtil.assetCode2Chain(assetCode));
|
|
|
|
|
- EthGetTransactionCount ethGetTransactionCount = web3j
|
|
|
|
|
- .ethGetTransactionCount(address, DefaultBlockParameterName.PENDING)
|
|
|
|
|
- .send();
|
|
|
|
|
- return ethGetTransactionCount.getTransactionCount();
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
private BigInteger toWei(String amount, Integer decimal) throws Exception {
|
|
private BigInteger toWei(String amount, Integer decimal) throws Exception {
|
|
|
// 简化的转换,实际需要处理小数
|
|
// 简化的转换,实际需要处理小数
|
|
|
BigDecimal pow = BigDecimal.TEN.pow(decimal);
|
|
BigDecimal pow = BigDecimal.TEN.pow(decimal);
|
|
@@ -433,7 +343,6 @@ public class EthereumService implements BlockchainService {
|
|
|
* @param address
|
|
* @param address
|
|
|
* @return
|
|
* @return
|
|
|
*/
|
|
*/
|
|
|
- @Override
|
|
|
|
|
public boolean validateAddress(String address) {
|
|
public boolean validateAddress(String address) {
|
|
|
return CryptoUtil.validateEthAddress(address);
|
|
return CryptoUtil.validateEthAddress(address);
|
|
|
}
|
|
}
|
|
@@ -441,9 +350,9 @@ public class EthereumService implements BlockchainService {
|
|
|
/**
|
|
/**
|
|
|
* 通过hash获取交易信息
|
|
* 通过hash获取交易信息
|
|
|
*/
|
|
*/
|
|
|
- @Override
|
|
|
|
|
public TransactionInfoDTO getTransactionInfoByHash(String assetCode, String transactionHash) throws Exception {
|
|
public TransactionInfoDTO getTransactionInfoByHash(String assetCode, String transactionHash) throws Exception {
|
|
|
String chain = aUtil.assetCode2Chain(assetCode);
|
|
String chain = aUtil.assetCode2Chain(assetCode);
|
|
|
|
|
+ ChainCoinDetail chainCoinDetail = ChainCoinDetailManager.getChainCoinDetail(assetCode);
|
|
|
// 查询交易回执
|
|
// 查询交易回执
|
|
|
EthGetTransactionReceipt receiptResponse = Web3jManager.getWeb3j(chain).ethGetTransactionReceipt(transactionHash).send();
|
|
EthGetTransactionReceipt receiptResponse = Web3jManager.getWeb3j(chain).ethGetTransactionReceipt(transactionHash).send();
|
|
|
Optional<TransactionReceipt> receiptOpt = receiptResponse.getTransactionReceipt();
|
|
Optional<TransactionReceipt> receiptOpt = receiptResponse.getTransactionReceipt();
|
|
@@ -519,5 +428,4 @@ public class EthereumService implements BlockchainService {
|
|
|
if (hex.length() >= length) return hex;
|
|
if (hex.length() >= length) return hex;
|
|
|
return "0".repeat(length - hex.length()) + hex;
|
|
return "0".repeat(length - hex.length()) + hex;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
}
|
|
}
|