web3j入门实战,构建你自己的以太坊钱包
以太坊作为领先的智能合约平台,其生态系统中的钱包功能是用户与区块链交互的核心,无论是管理资产、发送交易,还是与DApp交互,一个安全可靠的以太坊钱包都至关重要,对于Java开发者而言,web3j库提供了一套强大且易用的工具,使得在Java应用中集成以太坊功能、开发自定义钱包变得相对简单,本文将带你了解如何使用web3j来开发展发以太坊钱包,涵盖从环境搭建到核心功能实现的关键步骤。
什么是web3j
在开始之前,我们先简单了解一下web3j,web3j是一个轻量级、响应式的Java和Android库,用于与以太坊节点进行交互,它提供了与以太坊JSON-RPC API的完整封装,允许开发者在不深入底层细节的情况下,实现账户管理、交易签名、智能合约交互、事件监听等功能,web3j支持同步和异步调用,非常适合构建各种类型的以太坊应用,包括钱包。
准备工作:环境搭建与依赖引入
- Java开发环境:确保你已经安装了JDK 8或更高版本,并配置好JAVA_HOME环境变量。
- 构建工具:Maven或Gradle,本文以Maven为例。
- 以太坊节点:你需要一个连接的以太坊节点,可以是本地节点(如Geth、Parity),也可以是远程节点服务(如Infura、Alchemy),对于开发阶段,使用Infura等远程服务是最便捷的选择。
- 引入web3j依赖:在你的Maven项目的
pom.xml文件中添加web3j核心依赖:<dependency> <groupId>org.web3j</groupId> <artifactId>core</artifactId> <version>4.9.8</version> <!-- 请使用最新版本 --> </dependency>
核心步骤:使用web3j开发以太坊钱包
开发一个基本的以太坊钱包,主要涉及以下几个核心步骤:
生成钱包(创建账户)
以太坊钱

WalletUtils类来简化钱包的创建过程。
import org.web3j.crypto.WalletUtils;
import java.io.File;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
public class WalletCreation {
public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
// 设置钱包文件存储目录
String walletDir = "wallets"; // 确保此目录存在或有权限创建
File directory = new File(walletDir);
if (!directory.exists()) {
directory.mkdirs();
}
// 生成新钱包,密码为"your-password",默认使用轻量级级联加密
String walletFileName = WalletUtils.generateNewWalletFile("your-password", directory);
System.out.println("钱包文件已创建: " + walletFileName);
// 生成BIP39格式的助记词钱包(更推荐,便于备份)
String mnemonic = WalletUtils.generateBip44 mnemonic(); // 生成助记词
System.out.println("助记词: " + mnemonic);
// 使用助记词和密码创建钱包文件
String bip44WalletFileName = WalletUtils.generateWalletFileFromBip44Mnemonic("your-password", mnemonic, directory, false);
System.out.println("BIP44钱包文件已创建: " + bip44WalletFileName);
}
}
执行上述代码后,你会在指定的walletDir目录下看到以UTC--开头的钱包文件,这就是你的以太坊钱包文件,包含了加密的私钥。务必妥善保管钱包文件和你的密码,一旦丢失,将无法恢复资产!
加载钱包(解锁账户)
要使用已存在的钱包,你需要提供钱包文件路径和密码来加载凭证(Credentials)。
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import java.io.File;
import java.math.BigInteger;
public class WalletLoading {
public static void main(String[] args) throws Exception {
// 连接到以太坊节点(以Infura为例)
Web3j web3j = Web3j.build(new HttpService("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID"));
// 钱包文件路径和密码
String walletFilePath = "wallets/UTC--...your-wallet-file-name";
String password = "your-password";
// 加载钱包凭证
Credentials credentials = WalletUtils.loadCredentials(password, walletFilePath);
String address = credentials.getAddress();
BigInteger privateKey = credentials.getEcKeyPair().getPrivate();
System.out.println("钱包地址: " + address);
System.out.println("私钥 (十六进制): " + privateKey.toString(16));
}
}
注意:在实际应用中,私钥的打印和存储要极其小心,切勿泄露。
查询账户余额
加载钱包后,你可以查询该地址的以太坊余额。
import org.web3j.protocol.core.methods.response.EthGetBalance;
import java.io.IOException;
import java.math.BigInteger;
public class GetBalance {
public static void main(String[] args) throws IOException {
Web3j web3j = Web3j.build(new HttpService("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID"));
String address = "0x..."; // 替换为你的钱包地址
// 查询余额,单位是Wei
EthGetBalance ethGetBalance = web3j.ethGetBalance(address, org.web3j.protocol.core.DefaultBlockParameterName.LATEST).send();
BigInteger balanceWei = ethGetBalance.getBalance();
// 将Wei转换为Ether
BigInteger etherInWei = new BigInteger("1000000000000000000"); // 1 Ether in Wei
String balanceEther = balanceWei.divide(etherInWei).toString();
System.out.println("地址: " + address);
System.out.println("余额: " + balanceEther + " ETH");
}
}
发送以太坊交易
发送交易是钱包的核心功能之一,你需要指定接收方地址、转账金额、gas价格和gas限制等参数。
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
public class SendTransaction {
public static void main(String[] args) throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
Web3j web3j = Web3j.build(new HttpService("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID"));
// 加载发送方钱包
String senderWalletFilePath = "wallets/UTC--...your-sender-wallet-file";
String password = "your-password";
Credentials senderCredentials = WalletUtils.loadCredentials(password, senderWalletFilePath);
String senderAddress = senderCredentials.getAddress();
// 接收方地址和转账金额(0.1 ETH)
String receiverAddress = "0x..."; // 替换为接收方地址
BigDecimal amountInEth = new BigDecimal("0.1");
BigInteger value = Convert.toWei(amountInEth, Convert.Unit.ETHER).toBigIntegerExact();
// 获取nonce
EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(senderAddress, DefaultBlockParameterName.LATEST).send();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
// 设置gas参数 (可根据实际情况调整)
BigInteger gasLimit = BigInteger.valueOf(21000); // 转账ETH的典型gasLimit
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); // 获取当前建议gasPrice
// 创建原始交易
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
nonce, gasPrice, gasLimit, receiverAddress, value);
// 签名交易
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, senderCredentials);
String hexValue = Numeric.toHexString(signedMessage);
// 发送交易
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).send();
String transactionHash = ethSendTransaction.getTransactionHash();
System.out.println("交易已发送,交易哈希: " + transactionHash);
}
}
进阶功能与安全考虑
**BIP39