web3j入门实战,构建你自己的以太坊钱包

投稿 2026-03-12 18:30 点击数: 1

以太坊作为领先的智能合约平台,其生态系统中的钱包功能是用户与区块链交互的核心,无论是管理资产、发送交易,还是与DApp交互,一个安全可靠的以太坊钱包都至关重要,对于Java开发者而言,web3j库提供了一套强大且易用的工具,使得在Java应用中集成以太坊功能、开发自定义钱包变得相对简单,本文将带你了解如何使用web3j来开发展发以太坊钱包,涵盖从环境搭建到核心功能实现的关键步骤。

什么是web3j

在开始之前,我们先简单了解一下web3j,web3j是一个轻量级、响应式的Java和Android库,用于与以太坊节点进行交互,它提供了与以太坊JSON-RPC API的完整封装,允许开发者在不深入底层细节的情况下,实现账户管理、交易签名、智能合约交互、事件监听等功能,web3j支持同步和异步调用,非常适合构建各种类型的以太坊应用,包括钱包。

准备工作:环境搭建与依赖引入

  1. Java开发环境:确保你已经安装了JDK 8或更高版本,并配置好JAVA_HOME环境变量。
  2. 构建工具:Maven或Gradle,本文以Maven为例。
  3. 以太坊节点:你需要一个连接的以太坊节点,可以是本地节点(如Geth、Parity),也可以是远程节点服务(如Infura、Alchemy),对于开发阶段,使用Infura等远程服务是最便捷的选择。
  4. 引入web3j依赖:在你的Maven项目的pom.xml文件中添加web3j核心依赖:
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>core</artifactId>
        <version>4.9.8</version> <!-- 请使用最新版本 -->
    </dependency>

核心步骤:使用web3j开发以太坊钱包

开发一个基本的以太坊钱包,主要涉及以下几个核心步骤:

生成钱包(创建账户)

以太坊钱

随机配图
包的本质是一个密钥对,由私钥和公钥组成,其中公钥通过Keccak-256哈希算法生成以太坊地址,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