1. 引入 pom 文件
org.web3j
core
4.5.5
2. https://infura.io/测试网站 web3j 的 api
获取测试币种步骤 https://www.jianshu.com/p/89aa70bdbb4d
https://twitter.com/中的账号 2270506143@qq.com 密码*****.com
3. 测试 url 获取步骤
进入 https://infura.io/docs 使用邮箱注册
账号密码:lpn199501@gmail.com/Admin1@dxoption
4. java 代码如下:
代码中的 url:https://rinkeby.infura.io/v3/603a3ce24ee04e32a1201a6a9e1072cf
package com.common.wallet.client.impl;
import com.common.wallet.client.ICoinClient;
import com.common.wallet.dto.TransactionsDTO;
import com.common.wallet.dto.WalletBalanceDTO;
import com.common.wallet.dto.WalletGetAddressDTO;
import com.common.wallet.dto.WalletSendToAddressDTO;
import com.common.wallet.util.*;
import com.common.wallet.vo.TransactionVO;
import com.common.wallet.vo.WalletGetAddressVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.web3j.crypto.*;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.Transaction;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class EthCoinClient implements ICoinClient{
private Web3j web3j = null;
public EthCoinClient(String url) {
web3j = Web3j.build(new HttpService(url));
}
/**
* 获取转账地址
* @param walletGetAddressDTO
* @return
*/
@Override
public
DataModel
walletGetAddressDTO) {
try {
getGetNewAddress(WalletGetAddressDTO
log.info("ETH 系 列 进 入 获 取 转 账 地 址 getGetNewAddress 方 法 {}",
walletGetAddressDTO.toString());
final ECKeyPair keyPair = Keys.createEcKeyPair();
final
org.web3j.crypto.Credentials
credentials
=
org.web3j.crypto.Credentials.create(keyPair);
final String passphrase = credentials.getEcKeyPair().getPrivateKey().toString(16);
final String address = credentials.getAddress();
return
new
DataModel<>(ResultStatusEnum.OK,new
WalletGetAddressVO(address,passphrase));
} catch (Exception e) {
log.error("ETH 系列钱包服务(getGetNewAddress)方法出错{}", e);
return new DataModel<>(ResultStatusEnum.WALLET_GETADDRESS_ERROR);
}
}
/**
* 验证转账地址
* @param address
* @return
*/
@Override
public DataModel validateAddress(String address) {
try {
log.info("ETH 系列进入验证转账地址 validateAddress 方法{}",address);
boolean isValid = false;
if (isValidAddress(address)) {
isValid = true;
}
return new DataModel<>(ResultStatusEnum.OK,isValid);
} catch (Exception e) {
log.error("ETH 系列验证转账地址(validateAddress)方法出错{}", e);
return
new
DataModel<>(ResultStatusEnum.WALLET_VALIDATEADDRESS_ERROR,false);
}
}
/**
* 通过 private key 生成 credentials
*/
public static Credentials generateCredentials(String privateKey) {
return Credentials.create(privateKey);
}
/**
* 转账
* @param walletSendToAddressDTO fromAddress 转出地址,Amount 转出数量,ToAddress
转入地址,PrivateKey 转出地址私钥
* @return
*/
@Override
public DataModel sendToAddress(WalletSendToAddressDTO walletSendToAddressDTO) {
try {
log.info("ETH 系 列 进 入 验 证 转 账 validateAddress 方 法 , 转 账 数 据
{}",walletSendToAddressDTO.toString());
BigInteger
nonce
=
web3j.ethGetTransactionCount(walletSendToAddressDTO.getFromAddress(),
DefaultBlockParameterName.PENDING).send().getTransactionCount();
/*BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
BigInteger gasLimit = BigInteger.valueOf(21000L);*/
//支付该笔交易每个单元的 gas 的价格,单位是 wei(将 BigDecimal 转换成 wei)
= Convert.toWei(walletSendToAddressDTO.getGasPrice(),
BigInteger
gasPrice
Convert.Unit.GWEI).toBigInteger();
//支付该笔交易最大数量的 gas(将 BigDecimal 转换成 wei)
BigInteger
= Convert.toWei(walletSendToAddressDTO.getGasLimit(),
gasLimit
Convert.Unit.GWEI).toBigInteger();
//转账数量(数量乘以 18 次幂)
BigInteger amountWei = Convert.toWei(walletSendToAddressDTO.getAmount(),
Convert.Unit.ETHER).toBigInteger();
RawTransaction
rawTransaction
=
RawTransaction.createTransaction(nonce,
gasPrice, gasLimit, walletSendToAddressDTO.getToAddress(), amountWei, "");
byte[]
signMessage
=
TransactionEncoder.signMessage(rawTransaction,
generateCredentials(walletSendToAddressDTO.getPrivateKey()));
String
=
web3j.ethSendRawTransaction(Numeric.toHexString(signMessage)).sendAsync().get().getTransac
tionHash();
result
return new DataModel<>(ResultStatusEnum.OK,result);
} catch (Exception e) {
log.error("ETH 系列转账(sendToAddress)方法出错{}", e);
return new DataModel<>(ResultStatusEnum.WALLET_SENDTOADDRESS_ERROR);
}
}
/**
* 根据 txid 查询用户交易信息
* @param txId
* @return
*/
@Override
public DataModel getTransaction(String txId) {
try {
log.info("ETH 系列查询用户交易信息 getTransaction 方法,txid{}",txId);
Transaction
transaction
=
web3j.ethGetTransactionByHash(txId).send().getTransaction().get();
TransactionVO transactionVO = new TransactionVO();
transactionVO.setToAddress(transaction.getTo());
transactionVO.setCategory("ETH");
///转账数量,数量除以 1 的 18 次幂
BigDecimal amount = Convert.fromWei(String.valueOf(transaction.getValue()),
Convert.Unit.ETHER);
transactionVO.setAmount(amount);
transactionVO.setTxId(transaction.getHash());
return new DataModel<>(ResultStatusEnum.OK, transactionVO);
} catch (Exception e) {
log.error("ETH 系列查询用户交易信息(getTransaction)方法出错{}", e);
return
new
DataModel<>(ResultStatusEnum.WALLET_GETTRANSACTIONBYTXID_ERROR);
}
}
/**
* 根据钱包 id 查询,拉取交易信息
* @return count 系统累加区块高度,numberPlus 要查询区块的数量
*/
@Override
public DataList listTransactions(TransactionsDTO transactionsDTO) {
try {
log.info("ETH 系列拉取交易信息方法{}", transactionsDTO.toString());
//获取当前块高度
BigInteger
currentBlockNumber
=
web3j.ethBlockNumber().send().getBlockNumber();
//查询区块的截止位置(系统累加区块高度 ount+查询区块数量 numberPlus)
=
BigInteger
lastBlockNumber
BigInteger.valueOf(transactionsDTO.getCount()+transactionsDTO.getNumberPlus());
//查询的区块高度
if (lastBlockNumber.compareTo(currentBlockNumber) > 0) {
log.error(">>>>系统累加区块高度:" + transactionsDTO.getAccount() + ",
"ETH 区块高度:" + currentBlockNumber
缓冲区块高度:" + lastBlockNumber + ",大于当前" +
+ "跳出拉取<<<<");
return
new
DataList(ResultStatusEnum.WALLET_LISTTRANSACTIONS_ETH_HEIGHT_ERROR);
}
long futureBlockNum = lastBlockNumber.intValue() + 1;
List list = new ArrayList();
//遍历区块
for (int i = transactionsDTO.getCount(); i < futureBlockNum; i++) {
//获取 block
EthBlock.Block
block
web3j.ethGetBlockByNumber(DefaultBlockParameter.valueOf(BigInteger.valueOf(i)),
true).send().getBlock();
if (block == null) {
continue;
}
// 遍历 block 中的交易
for (EthBlock.TransactionResult tx : block.getTransactions()) {
if (tx instanceof EthBlock.TransactionObject) {
//transaction: 块中的单笔交易
EthBlock.TransactionObject
transaction
(EthBlock.TransactionObject) tx;
TransactionVO transactionVO = new TransactionVO();
transactionVO.setToAddress(transaction.getTo());
transactionVO.setCategory("ETH");
//转账数量,数量除以 1 的 18 次幂
BigDecimal
amount
Convert.fromWei(String.valueOf(transaction.getValue()), Convert.Unit.ETHER);
transactionVO.getAmount());
transactionVO.setAmount(amount);
transactionVO.setFromAddress(transaction.getFrom());
log.debug(transactionVO.getToAddress()
+
"\t"
transactionVO.setTxId(transaction.getHash());
list.add(transactionVO);
=
=
=
+
}
}
}
if(list.size() > 0){
return new DataList(ResultStatusEnum.OK,list);
}
return new DataList(ResultStatusEnum.WALLET_LISTTRANSACTIONS_IS_NULL);
} catch(Exception e){
log.error("ETH 系列拉取交易信息(listTransactions)方法出错{}", e);
return new DataList(ResultStatusEnum.WALLET_LISTTRANSACTIONS_ERROR);
}
}
/**
* 当前区块高度查询
* @return
*/
@Override
public DataModel getBlockCount() {
try {
log.info("ETH 系列拉取交易信息方法!");
BigInteger ethBlockNumber = web3j.ethBlockNumber().send().getBlockNumber();
return new DataModel(ResultStatusEnum.OK,ethBlockNumber);
} catch (Exception e) {
log.error("ETH 系列钱包获取区块高度(getBlockCount)方法出错{}", e);
return new DataModel<>(ResultStatusEnum.WALLET_GETBLOCKCOUNT_ERROR);
}
}
/**
* 查询区块差(当前区块-交易所在区块+1)
* @param txId
* @return
*/
@Override
public DataModel getBlockDiffer(String txId) {
try {
log.info("ETH 系列查询区块差方法,txId{}",txId);
DataModel dataModelBlock = this.getBlockCount();
if(dataModelBlock.getCode() != ResultStatusEnum.OK.getCode()){
return dataModelBlock;
}
BigInteger blockCount = (BigInteger)dataModelBlock.getModel();
Transaction
transaction
web3j.ethGetTransactionByHash(txId).send().getTransaction().get();
=
blockCount
=
blockCount.subtract(transaction.getBlockNumber()).add(new
BigInteger("1"));
return new DataModel<>(ResultStatusEnum.OK,blockCount);
} catch (Exception e) {
log.error("ETH 查询区块差,交易信息(getBlockCount)方法出错{}", e);
return new DataModel<>(ResultStatusEnum.WALLET_GETBLOCKDIFFER_ERROR);
}
}
/**
* 查询钱包余额
* @return
*/
@Override
public DataModel getBalance(WalletBalanceDTO walletBalanceDTO) {
BigInteger balance = new BigInteger("0");
try {
log.info("ETH 系列查询钱包余额方法,address{}",walletBalanceDTO.toString());
balance
=
web3j.ethGetBalance(walletBalanceDTO.getAddress(),
DefaultBlockParameterName.PENDING).send().getBalance();
///转账数量,数量除以 1 的 18 次幂
BigDecimal
amount
=
Convert.fromWei(String.valueOf(balance),
Convert.Unit.ETHER);
return new DataModel<>(ResultStatusEnum.OK,amount);
}catch (Exception e){
log.error("ETH 系列,查询钱包余额(getbalance)方法出错{}",e);
return
DataModel<>(ResultStatusEnum.WALLET_GETBALANCE_ERROR,
new
balance);
}
}
private boolean isValidAddress(String addr) {
String regex = "^0x[0-9a-fA-F]{40}$";
//Print for testing purpose and more verbose output
//
System.out.println("Incoming Address " + addr);
if (addr.matches(regex)) {
return true;
}
return false;
}
}