Java实现以太坊钱包,从零开始构建你的数字资产管理工具

默认分类 2026-03-18 11:15 19 0

以太坊作为全球第二大区块链平台,其原生代币ETH以及基于ERC标准的代币(如USDT、USDC等)的普及,使得个人钱包的管理变得日益重要,虽然市面上已有众多成熟的以太坊钱包应用,但对于开发者而言,使用Java语言从零开始搭建一个属于自己的以太坊钱包,不仅能深入理解区块链技术的底层原理,还能为开发更复杂的去中心化应用(DApp)或金融服务打下坚实基础,本文将详细介绍如何使用Java语言搭建一个基础的以太坊钱包。

准备工作:开发环境与依赖

在开始之前,我们需要准备以下环境和工具:

  1. Java开发环境:确保你的系统已安装JDK 8或更高版本,并配置好JAVA_HOME环境变量。
  2. 构建工具随机配图
ng>:Maven或Gradle,本文以Maven为例。
  • 以太坊客户端库:我们将使用成熟的Java以太坊库web3j,它提供了与以太坊节点交互的丰富API,包括创建钱包、查询余额、发送交易等。
  • 以太坊节点:可以连接到公共的以太坊节点(如Infura、Alchemy),或者运行本地节点(如Geth或Parity),对于开发测试,公共节点更为便捷。
  • 创建Maven项目并引入依赖

    创建一个Maven项目,并在pom.xml文件中添加web3j的核心依赖:

    <dependencies>
        <!-- Web3j核心库 -->
        <dependency>
            <groupId>org.web3j</groupId>
            <artifactId>core</artifactId>
            <version>4.9.8</version> <!-- 请使用最新版本 -->
        </dependency>
        <!-- 用于生成 solidity 相关代码的依赖 (可选) -->
        <dependency>
            <groupId>org.web3j</groupId>
            <artifactId>codegen</artifactId>
            <version>4.9.8</version>
        </dependency>
        <!-- 日志依赖 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.36</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.11</version>
        </dependency>
    </dependencies>

    生成以太坊钱包(创建账户)

    以太坊钱包的核心是账户,每个账户由一对公钥和私钥组成,其中私钥用于签名交易,公钥和地址则用于接收资金。web3j提供了方便的工具来生成和管理这些密钥。

    创建一个新的Java类WalletGenerator,编写以下代码来生成一个新钱包:

    import org.web3j.crypto.CipherException;
    import org.web3j.crypto.ECKeyPair;
    import org.web3j.crypto.Keys;
    import org.web3j.crypto.Wallet;
    import org.web3j.crypto.WalletFile;
    import java.io.File;
    import java.io.IOException;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    public class WalletGenerator {
        public static void main(String[] args) {
            try {
                // 1. 生成随机密钥对
                ECKeyPair ecKeyPair = Keys.createEcKeyPair();
                // 2. 根据密钥对创建钱包文件 (默认使用Scrypt加密算法)
                WalletFile walletFile = Wallet.createStandard("your-password", ecKeyPair); // "your-password"是你为钱包设置的密码
                // 3. 将钱包文件保存到本地
                String walletDir = "wallets"; // 钱包存储目录
                File walletFileObj = new File(walletDir);
                if (!walletFileObj.exists()) {
                    walletFileObj.mkdirs();
                }
                String fileName = walletFile.getAddress() + ".json";
                WalletUtils.saveWalletFile(new File(walletDir, fileName), walletFile);
                System.out.println("钱包创建成功!");
                System.out.println("钱包地址: " + walletFile.getAddress());
                System.out.println("私钥 (请妥善保管,切勿泄露): " + org.web3j.crypto.WalletUtils.privateKeyFromKeyPair(ecKeyPair).toString(16));
                System.out.println("钱包文件已保存至: " + walletDir + File.separator + fileName);
            } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException | CipherException | IOException e) {
                e.printStackTrace();
            }
        }
    }

    说明

    • Keys.createEcKeyPair():生成随机的椭圆曲线密钥对。
    • Wallet.createStandard(password, ecKeyPair):使用标准算法(Scrypt)创建钱包文件,需要设置一个密码。
    • WalletUtils.saveWalletFile():将钱包文件保存到指定目录,钱包文件是一个JSON文件,包含地址、加密的私钥等信息。
    • 重要:私钥是控制钱包资产的关键,生成后必须极其小心地保存,绝对不要泄露给他人,在实际应用中,私钥的存储需要极高的安全性。

    运行上述代码,你将在wallets目录下看到一个以钱包地址命名的.json文件,这就是你的以太坊钱包文件。

    加载钱包与查询余额

    生成钱包后,我们需要能够加载它并进行操作,比如查询账户余额。

    创建WalletManager类:

    import org.web3j.crypto.CipherException;
    import org.web3j.crypto.WalletUtils;
    import org.web3j.protocol.Web3j;
    import org.web3j.protocol.core.methods.response.EthGetBalance;
    import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
    import org.web3j.protocol.core.methods.response.EthSendTransaction;
    import org.web3j.protocol.core.methods.response.TransactionReceipt;
    import org.web3j.protocol.http.HttpService;
    import org.web3j.utils.Convert;
    import org.web3j.utils.Convert.Unit;
    import org.web3j.utils.Numeric;
    import java.io.File;
    import java.io.IOException;
    import java.math.BigDecimal;
    import java.math.BigInteger;
    public class WalletManager {
        // 替换为你的Infura或Alchemy节点URL
        private static final String INFURA_URL = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID";
        private static final String WALLET_DIR = "wallets";
        private static final String WALLET_PASSWORD = "your-password";
        public static void main(String[] args) {
            // 1. 连接到以太坊节点
            Web3j web3j = Web3j.build(new HttpService(INFURA_URL));
            try {
                // 2. 加载钱包 (假设我们已经有了一个钱包文件)
                String walletFileName = "YOUR_WALLET_ADDRESS.json"; // 替换为你的钱包文件名
                File walletFile = new File(WALLET_DIR, walletFileName);
                // 3. 解析钱包文件,获取Credentials对象
                org.web3j.crypto.Credentials credentials = WalletUtils.loadCredentials(WALLET_PASSWORD, walletFile);
                String walletAddress = credentials.getAddress();
                System.out.println("钱包地址: " + walletAddress);
                // 4. 查询账户余额
                EthGetBalance balance = web3j.ethGetBalance(walletAddress, org.web3j.protocol.core.DefaultBlockParameterName.LATEST).send();
                BigInteger balanceWei = balance.getBalance();
                BigDecimal balanceEth = Convert.fromWei(new BigDecimal(balanceWei), Unit.ETHER);
                System.out.println("账户余额: " + balanceEth + " ETH");
                // 5. (可选) 查询nonce (交易次数)
                EthGetTransactionCount nonce = web3j.ethGetTransactionCount(walletAddress, org.web3j.protocol.core.DefaultBlockParameterName.LATEST).send();
                BigInteger transactionCount = nonce.getTransactionCount();
                System.out.println("Nonce: " + transactionCount);
                // 6. (可选) 发送ETH (这里仅作示例,实际发送需要足够的ETH支付gas费)
                /*
                String toAddress = "0xRecipientAddressHere";
                BigInteger value = Convert.toWei("0.01", Unit.ETHER).toBigInteger();
                BigInteger gasLimit = BigInteger.valueOf(21000); // 转账ETH通常21000 gas
                BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); // 获取当前建议gas价格
                EthSendTransaction transaction = web3j.ethSendTransaction(
                        org.web3j.protocol.core.methods.Transaction.createEtherTransaction(
                                walletAddress,
                                nonce.getTransactionCount(),
                                gasPrice,
                                gasLimit,
                                toAddress,
                                value))
                        .send();
                if (transaction.getTransactionHash() != null) {
                    System.out.println("交易发送成功,哈希: " + transaction.getTransactionHash());
                    // 等待交易被打包
                    TransactionReceipt receipt = web3j.ethGetTransactionReceipt(transaction.getTransactionHash()).send().getTransactionReceipt().orElse(null);
                    if (receipt != null) {
                        System.out.println("交易状态: " + receipt.getStatus());
                    }
                } else {
                    System.out.println("交易发送失败: " + transaction.getError().getMessage());
                }
                */