
在Web3的世界里,钱包不仅仅是一个存放资产的工具,更是用户通往去中心化应用的入口。与Web2的“忘记密码”机制不同,Web3钱包的核心是私钥管理——谁掌握了私钥,谁就掌握了资产。本文将从零开始,带你搭建一个支持以太坊(ETH)和币安智能链(BSC)的非托管钱包。

在着手编码之前,必须理解钱包的底层逻辑。Web3钱包之所以没有“找回密码”功能,是因为它不依赖中心化服务器存储用户凭证。钱包的构成遵循以下链条:
随机数 → 私钥 → 公钥 → 地址
其中,助记词(BIP39标准)是这一切的起点。它由12或24个单词组成,通过算法可推导出所有私钥。开发时,我们主要依赖bip39和bip32库来实现这个派生过程,常用的以太坊HD路径是m/44'/60'/0'/0/0。这套机制的妙处在于:一套助记词即可管理多链资产,因为ETH和BSC同为EVM兼容链,可以使用相同的派生路径生成地址。
开发钱包,我们要避免“重复造轮子”,核心库选型至关重要:
交互层:推荐使用ethers.js或viem。前者社区生态成熟,文档丰富,适合初学者快速上手;后者采用模块化设计,对TypeScript支持更友好,适合追求代码健壮性的项目。
账户层:使用bip39生成助记词,bip32实现分层确定性派生。
存储层:绝对禁止明文存储私钥。在Web端,应使用用户设置的密码对私钥进行AES加密后存储在localStorage;在移动端(如React Native),应调用系统安全存储(如iOS Keychain或Android Keystore)。
在架构上,建议采用插件化设计。将“链交互”抽象为统一接口(如getBalance, sendTransaction),ETH和BSC作为该接口的不同实现类。这样未来扩展Polygon或Arbitrum时,只需新增适配器,无需重构核心代码。
这是钱包的“出生”环节。利用bip39生成助记词,再利用ethers.js的HDNode派生钱包。
import * as bip39 from 'bip39';import { ethers } from 'ethers';// 1. 生成助记词(此处为12位)const mnemonic = bip39.generateMnemonic(128); // 提示:务必引导用户备份此助记词// 2. 派生ETH/BSC钱包(两者路径一致)const seed = await bip39.mnemonicToSeed(mnemonic);const hdNode = ethers.utils.HDNode.fromSeed(seed);const path = "m/44'/60'/0'/0/0"; // BIP44标准路径const childNode = hdNode.derivePath(path);const wallet = new ethers.Wallet(childNode.privateKey);console.log('Address:', wallet.address);console.log('Private Key:', wallet.privateKey);钱包需要读取链上数据。由于运行全节点成本高昂,我们通常接入第三方节点服务商(如Infura、Ankr)提供的RPC URL。
// ETH主网与BSC主网的RPC配置const ETH_RPC = "https://mainnet.infura.io/v3/YOUR_KEY";const BSC_RPC = "https://bsc-dataseed.binance.org/";const provider = new ethers.providers.JsonRpcProvider(ETH_RPC);const balance = await provider.getBalance(wallet.address);console.log(`ETH Balance: ${ethers.utils.formatEther(balance)}`);发起转账是钱包的核心操作。无论ETH还是BSC,逻辑基本一致,仅需切换对应的Provider即可。
const sendTx = async (toAddress: string, amountInEth: string) => {
// 使用私钥实例化Wallet并连接Provider
const signer = wallet.connect(provider);
const tx = await signer.sendTransaction({
to: toAddress,
value: ethers.utils.parseEther(amountInEth),
gasLimit: 21000, // 常规转账
});
await tx.wait(); // 等待链上确认
console.log('Tx Hash:', tx.hash);};由于ETH和BSC均采用EVM,代码复用度极高。你只需在UI层增加一个“网络切换”按钮,用于动态切换provider指向的RPC端点即可。
安全是钱包的生命线。在开发过程中,必须牢记两点:
一个存放资产的工具,更是用户通往去中心化应用的入口。与Web2的“忘记密码”机制不同,Web3钱包的核心是私钥管理——谁掌握了私钥,谁就掌握了资产。本文将从零开始,带你搭建一个支持以太坊(ETH)和币安智能链(BSC)的非托管钱包。
在着手编码之前,必须理解钱包的底层逻辑。Web3钱包之所以没有“找回密码”功能,是因为它不依赖中心化服务器存储用户凭证。钱包的构成遵循以下链条:
随机数 → 私钥 → 公钥 → 地址
其中,助记词(BIP39标准)是这一切的起点。它由12或24个单词组成,通过算法可推导出所有私钥。开发时,我们主要依赖bip39和bip32库来实现这个派生过程,常用的以太坊HD路径是m/44'/60'/0'/0/0。这套机制的妙处在于:一套助记词即可管理多链资产,因为ETH和BSC同为EVM兼容链,可以使用相同的派生路径生成地址。
开发钱包,我们要避免“重复造轮子”,核心库选型至关重要:
交互层:推荐使用ethers.js或viem。前者社区生态成熟,文档丰富,适合初学者快速上手;后者采用模块化设计,对TypeScript支持更友好,适合追求代码健壮性的项目。
账户层:使用bip39生成助记词,bip32实现分层确定性派生。
存储层:绝对禁止明文存储私钥。在Web端,应使用用户设置的密码对私钥进行AES加密后存储在localStorage;在移动端(如React Native),应调用系统安全存储(如iOS Keychain或Android Keystore)。
在架构上,建议采用插件化设计。将“链交互”抽象为统一接口(如getBalance, sendTransaction),ETH和BSC作为该接口的不同实现类。这样未来扩展Polygon或Arbitrum时,只需新增适配器,无需重构核心代码。
这是钱包的“出生”环节。利用bip39生成助记词,再利用ethers.js的HDNode派生钱包。
import * as bip39 from 'bip39';import { ethers } from 'ethers';// 1. 生成助记词(此处为12位)const mnemonic = bip39.generateMnemonic(128); // 提示:务必引导用户备份此助记词// 2. 派生ETH/BSC钱包(两者路径一致)const seed = await bip39.mnemonicToSeed(mnemonic);const hdNode = ethers.utils.HDNode.fromSeed(seed);const path = "m/44'/60'/0'/0/0"; // BIP44标准路径const childNode = hdNode.derivePath(path);const wallet = new ethers.Wallet(childNode.privateKey);console.log('Address:', wallet.address);console.log('Private Key:', wallet.privateKey);钱包需要读取链上数据。由于运行全节点成本高昂,我们通常接入第三方节点服务商(如Infura、Ankr)提供的RPC URL。
// ETH主网与BSC主网的RPC配置const ETH_RPC = "https://mainnet.infura.io/v3/YOUR_KEY";const BSC_RPC = "https://bsc-dataseed.binance.org/";const provider = new ethers.providers.JsonRpcProvider(ETH_RPC);const balance = await provider.getBalance(wallet.address);console.log(`ETH Balance: ${ethers.utils.formatEther(balance)}`);发起转账是钱包的核心操作。无论ETH还是BSC,逻辑基本一致,仅需切换对应的Provider即可。
const sendTx = async (toAddress: string, amountInEth: string) => {
// 使用私钥实例化Wallet并连接Provider
const signer = wallet.connect(provider);
const tx = await signer.sendTransaction({
to: toAddress,
value: ethers.utils.parseEther(amountInEth),
gasLimit: 21000, // 常规转账
});
await tx.wait(); // 等待链上确认
console.log('Tx Hash:', tx.hash);};由于ETH和BSC均采用EVM,代码复用度极高。你只需在UI层增加一个“网络切换”按钮,用于动态切换provider指向的RPC端点即可。
安全是钱包的生命线。在开发过程中,必须牢记两点:
专注WEB3开发、区块链技术落地、数字钱包与交易所定制开发,深耕区块链底层技术与Web3生态构建,提供公链/联盟链部署、智能合约开发、多链钱包搭建、中心化/去中心化交易所定制等一站式技术解决方案。

