使用 Ethers.js + SolidJS 打造极简以太坊钱包

·

关键词:以太坊钱包、Ethers.js、SolidJS、Web3 入门、智能合约前端开发、去中心化应用、Sepolia 测试网、助记词、加密存储

为什么用 Ethers.js + SolidJS?

在 Web3 开发浪潮下,一个能演示 以太坊钱包 基本功能的演示项目最具学习价值。SolidJS 具备 React 相同的函数式体验,同时比 React 更快、更轻;而 Ethers.js 则是社区最受欢迎的链上交互库,二者结合能极致简化以太坊转账 Demo 原型。

前置知识与环境

第一步:用 Vite 初始化 SolidJS 项目

npm create vite@latest eth-wallet -- --template solid-ts
cd eth-wallet
npm i ethers crypto-js

第二步:架构梳理

  1. 用户首次进入 → 创建钱包
  2. 引导备份 助记词 → 加密 私钥localStorage
  3. 再次进入 → 输入密码 加载钱包
  4. 展示 地址、余额 并实现 发送 ETH

第三步:核心代码拆解

示例仅贴关键片段,可直接替换 src/App.tsx,完整文件见文末仓库地址。

3.1 状态定义

const [step, setStep] = createSignal(1);      // 1创建 2备份 3主界面
const [wallet, setWallet] = createSignal<Wallet | null>(null);
const [balance, setBalance] = createSignal('0');

3.2 创建钱包

const createWallet = async () => {
  const mnemonic = Wallet.createRandom().mnemonic.phrase;
  const hdWallet = HDNodeWallet.fromMnemonic(Mnemonic.fromPhrase(mnemonic));
  setPhrase(mnemonic);
  const provider = new JsonRpcProvider(import.meta.env.VITE_RPC_URL);
  hdWallet.connect(provider);
  setWallet(hdWallet);

  // AES 加密私钥
  const cipher = CryptoJS.AES.encrypt(hdWallet.privateKey, password()).toString();
  localStorage.setItem('encKey', cipher);
  setStep(2);
};

3.3 加载已有钱包

const loadWallet = async () => {
  const encKey = localStorage.getItem('encKey');
  const bytes = CryptoJS.AES.decrypt(encKey!, password());
  const privKey = bytes.toString(CryptoJS.enc.Utf8);
  const provider = new JsonRpcProvider(import.meta.env.VITE_RPC_URL);
  const restoredWallet = new Wallet(privKey, provider);
  setWallet(restoredWallet);
  const balRaw = await provider.getBalance(restoredWallet.address);
  setBalance(formatEther(balRaw));
  setStep(3);
};

3.4 UI 片段(SolidJS)

return (
  <>
    <Show when={step() === 1} keyed>
      <h2>输入密码 {key ? '解锁钱包' : '创建钱包'}</h2>
      <input type="password" onChange={e => setPassword(e.target.value)} />
      <button onClick={() => key ? loadWallet() : createWallet()}>
        {key ? '解锁' : '生成钱包'}
      </button>
    </Show>

    <Show when={step() === 2} keyed>
      <h3>📋 请抄写并离线保存 12 个助记词</h3>
      <pre>{phrase()}</pre>
      <button onClick={() => setStep(3)}>我已安全备份</button>
    </Show>

    <Show when={step() === 3} keyed>
      <div>
        <p>地址:{wallet()?.address}</p>
        <p>余额:{balance()} ETH</p>
        <input placeholder="收款地址" onChange={e => setRecipient(e.target.value)} />
        <input placeholder="数量 (ETH)" type="number" onChange={e => setAmount(e.target.value)} />
        <button onClick={sendEth}>转账</button>
        {txHash() && (
          <a href={`https://sepolia.etherscan.io/tx/${txHash()}`} target="_blank">
            查看 Tx
          </a>
        )}
      </div>
    </Show>
  </>
);
👉 在 5 分钟内从零构建可交互的以太坊钱包原型

第四步:发送 ETH 完整实现

const sendEth = async () => {
  try {
    const tx = await wallet()!.sendTransaction({
      to: recipient(),
      value: parseEther(amount())
    });
    setTxHash(tx.hash);
    // 刷新余额
    const balRaw = await wallet()!.provider.getBalance(wallet()!.address);
    setBalance(formatEther(balRaw));
  } catch (e) {
    alert(`转账失败: ${e}`);
  }
};

第五步:测试体验指南

  1. 准备测试币
    生成钱包后复制地址,到 Sepolia 水龙头领取 0.1 ETH 足矣。
  2. 转账演示
    将 0.05 ETH 转到另一个测试网地址,提交后 10 秒即可在 Sepolia Etherscan 看到交易状态。
  3. 热重载
    npm run dev 开启本地热更新,刷新页面可模拟“解锁”场景。

第六步:进阶路线图

👉 查看完整源码与技术栈清单,立即获取 Tutorial 仓库

FAQ:新手常见疑惑

Q1:助记词能丢吗?
A:请 同时 离线抄写两份,一份放家里一份放公司保险箱。任何线上笔记、邮箱都可能被扫描,助记词一旦泄漏资产即归零。

Q2:为何不多用硬件钱包签名?
A:这里只做教学演示版。在生产级 DApp 中,推荐使用 WalletConnect + 硬件钱包签名,私钥永远不进浏览器。

Q3:为何用 Sepolia 而非 Görli?
A:Sepolia 测试网有 充足水龙头、出块稳定且合并成功后能耗更低,2025 年官方也长期维护。

Q4:SolidJS 和 React 差距大吗?
A:语法相似度 90%,只是将 useState 替换为 createSignal,且响应式系统提前编译,性能更好,包体积更小。

Q5:crypto-js AES 安全吗?
A:基本抗暴力,但 防不了浏览器插件读取内存。生产场景应换用 WebCrypto APIArgon2 等更现代方案。

Q6:如何批量监听多笔交易状态?
A:可订阅 provider.on('block') 每区块轮询,补充 setInterval + Promise.all 以免接口限速。
若想实时推送,改用 Websocket 提供者(WebSocketProvider)订阅 pendingreceipt


至此,我们的极简以太坊钱包即完成。你可以把这段代码克隆到 GitHub,再扩展成公司 PoC 演示或 Hackathon 参赛作品。继续深挖 Web3 前端开发,不仅能感受区块链的新奇魅力,更能先人一步拥抱下一代互联网基础设施!