BTC转账功能开发
一、准备工作
1、下载metamask钱包插件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uQgfiZ6B-1660126639658)(/Users/wanping/Desktop/博文/btc/00001.png)]
根据提示使用助记词生成账户,这里可以看到用户可以保留助记词,但是不保留私钥,或者keystore的json文件。可以生成一个账户
2、创建账户
针对于java和以太坊之间操作,一般有两种生成账户的方法:
-
使用metamask插件运用助记词创建账户的方法
-
用代码生成账户的方法,该方法有一个好处就是我们能够掌握账户的私钥(keystore的json文件)
-
maven配置
<dependency> <groupId>org.bitcoinj</groupId> <artifactId>bitcoinj-core</artifactId> <version>0.14.7</version> </dependency> <dependency> <groupId>org.web3j</groupId> <artifactId>core</artifactId> <version>3.6.0</version> </dependency>
-
代码实现
/** * 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); /** * 创建钱包 * @throws MnemonicException.MnemonicLengthException */ private static void createWallet() throws MnemonicException.MnemonicLengthException { 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()); System.out.println(); System.out.println("助记词:"); System.out.println(str); System.out.println(); System.out.println("地址:"); System.out.println("0x"+address); System.out.println(); System.out.println("私钥:"); System.out.println("0x"+keyPair.getPrivateKey().toString(16)); System.out.println(); System.out.println("公钥:"); System.out.println(keyPair.getPublicKey().toString(16)); } public static void main(String[] args) throws Exception { //创建钱包 createWallet(); }
-
导入钱包
- 保存上述打印东西
- 打开小狐狸钱包,导入私钥
-
3、领取测试币
领取测试币地址5ETH:https://faucet.dimensions.network/
二、ETH转账交易
1、创建自己的以太坊节点地址
参考区块链同学给我的地址:https://docs.infura.io/infura/networks/ethereum/json-rpc-methods/eth_sendtransaction
先注册=》创建项目=〉进入自己的项目
选择项目属性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mbD4FyXM-1660126639660)(/Users/wanping/Desktop/博文/btc/00002.png)]
复制自己的测试网节点地址(下拉到自己的测试网地址)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xvd326d9-1660126639660)(/Users/wanping/Desktop/博文/btc/00003.png)]
2、代码编写
实现ETH转账
/**
* 连接web3 节点
*/
private final static Web3j web3j = Web3j.build(new HttpService("https://rinkeby.infura.io/v3/第一步的那个项目编号"));
/**
* ETH转账
* @throws IOException
* @throws ExecutionException
* @throws InterruptedException
*/
public static void signETHTransaction() throws IOException, ExecutionException, InterruptedException {
//发送方地址
String from = "0xe12A0E286C94747E9D8a67e18FBDF35D6B58C5B6";
//转账数量
String amount = "0.05";
//接收者地址
String to = "0x336185cc47e81422d8ff26fb9a7a9c4138ce3d2a";
//发送方私钥
String privateKey = "****";
//查询地址交易编号
BigInteger nonce = web3j.ethGetTransactionCount(from, DefaultBlockParameterName.PENDING).send().getTransactionCount();
//支付的矿工费
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
BigInteger gasLimit = new BigInteger("210000");
BigInteger amountWei = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger();
//签名交易
RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, to, amountWei, "");
Credentials credentials = Credentials.create(privateKey);
byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
//广播交易
String hash = web3j.ethSendRawTransaction(Numeric.toHexString(signMessage)).sendAsync().get().getTransactionHash();
System.out.println("hash:"+hash);
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4PrNQVlh-1660126639661)(/Users/wanping/Desktop/博文/btc/00006.png)]
转账结果
转账之前:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4tP8shx-1660126639662)(/Users/wanping/Desktop/博文/btc/00004.png)]
转账后:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5u9wJs4Z-1660126639663)(/Users/wanping/Desktop/博文/btc/00005.png)]
3、代币查询
由于没有ETH的代币,所以找区块链的同学转了点币安测试网的代币
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wiV6cRKI-1660126639663)(/Users/wanping/Desktop/博文/btc/00007.png)]
代币余额查询
/**
* 连接web3 节点
*/
private final static Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-2-s2.binance.org:8545/项目编号"));
private static final BigDecimal WEI = new BigDecimal(10000);
/**
* 获取ERC-20 token指定地址余额
*/
public static void getbscGetBalance() throws ExecutionException, InterruptedException {
String methodName = "balanceOf";
List<Type> inputParameters = new ArrayList<>();
List<TypeReference<?>> outputParameters = new ArrayList<>();
Address fromAddress = new Address("发送方地址");
inputParameters.add(fromAddress);
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("发送方地址", "合约地址", data);
EthCall ethCall;
BigDecimal balanceValue = BigDecimal.ZERO;
try {
ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
BigInteger value = BigInteger.valueOf(0);
if(results != null && results.size()>0){
value = (BigInteger)results.get(0).getValue();
}
balanceValue = new BigDecimal(value).divide(WEI, 6, RoundingMode.HALF_DOWN);
System.out.println(balanceValue.toBigInteger());
} catch (IOException e) {
e.printStackTrace();
}
}
查询余额结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxATEKRB-1660126639664)(/Users/wanping/Desktop/博文/btc/00008.png)]
4、代币转账
转账代码实现:
/**
* ETH代币转账
* @throws IOException
* @throws ExecutionException
* @throws InterruptedException
*/
public static void signTokenTransaction() throws IOException, ExecutionException, InterruptedException {
//发送方地址
String from = "0xe12A0E286C94747E9D8a67e18FBDF35D6B58C5B6";
//转账数量
String amount = "5";
//接收者地址
String to = "0x336185cC47e81422D8fF26fB9A7a9c4138Ce3D2A";
//发送方私钥
String privateKey = "****";
//代币合约地址
String coinAddress = "合约地址";
//查询地址交易编号
BigInteger nonce = web3j.ethGetTransactionCount(from, DefaultBlockParameterName.PENDING).send().getTransactionCount();
//支付的矿工费
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
BigInteger gasLimit = new BigInteger("210000");
Credentials credentials = Credentials.create(privateKey);
BigInteger amountWei = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger();
//封装转账交易
Function function = new Function(
"transfer",
Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(to),
new org.web3j.abi.datatypes.generated.Uint256(amountWei)),
Collections.<TypeReference<?>>emptyList());
String data = FunctionEncoder.encode(function);
//签名交易
RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, coinAddress, data);
byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
//广播交易
String hash = web3j.ethSendRawTransaction(Numeric.toHexString(signMessage)).sendAsync().get().getTransactionHash();
System.out.println("hash:"+hash);
}
执行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qfIp4W2v-1660126639665)(/Users/wanping/Desktop/博文/btc/00009.png)]
转账结果
转账之前
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lvNO4Y2i-1660126639666)(/Users/wanping/Desktop/博文/btc/00010.png)]
转账之后:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tjzUY7YE-1660126639666)(/Users/wanping/Desktop/博文/btc/00011.png)]