Web3钱包开发实战:构建一个支持多链的浏览器插件钱包

Web3钱包开发实战:构建一个支持多链的浏览器插件钱包

浏览器插件钱包是Web3用户最常用的入口,MetaMask的成功证明了这一形态的价值。本文将带你从零构建一个支持多链的插件钱包,涵盖项目架构、密钥管理、Provider注入、交易签名与多链适配等核心环节,走通从开发到加载测试的完整流程。

qw.png

一、项目架构设计

插件钱包基于Chrome Extension Manifest V3构建,核心由三部分组成:

项目结构:

text

wallet-extension/
├── manifest.json
├── src/
│   ├── background/      # service worker
│   ├── popup/           # React UI
│   ├── content/         # content script
│   ├── inject/          # window.ethereum 注入
│   └── core/            # 密钥、签名、多链逻辑


manifest.json关键配置:

json

{
  "manifest_version": 3,
  "name": "MultiChain Wallet",
  "permissions": ["storage", "activeTab"],
  "background": { "service_worker": "background.js" },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"],
    "run_at": "document_start"
  }],
  "web_accessible_resources": [{
    "resources": ["inject.js"],
    "matches": ["<all_urls>"]
  }]}


二、密钥管理

使用ethers.js或@scure/bip39生成助记词并派生账户:

javascript

import { HDNodeWallet, Mnemonic } from "ethers";// 生成12位助记词const mnemonic = Mnemonic.fromEntropy(randomBytes(16));// 按BIP-44派生:m/44'/60'/0'/0/0const wallet = HDNodeWallet.fromMnemonic(mnemonic, "m/44'/60'/0'/0/0");


助记词绝不明文存储。用PBKDF2或scrypt从用户密码派生密钥,AES-GCM加密后存入chrome.storage.local。解密仅在用户解锁后的会话内进行,且私钥应尽量缩短驻留内存的时间。

三、注入Provider与EIP-1193

Content Script在页面上下文中注入window.ethereum。由于MV3的隔离世界限制,需通过DOM事件或window.postMessage在injected script与content script间通信。

Injected Provider实现核心接口:

javascript

window.ethereum = {
  isMetaMask: false,
  request: async ({ method, params }) => {
    return new Promise((resolve, reject) => {
      const id = Date.now();
      const handler = (e) => {
        if (e.data.id !== id) return;
        window.removeEventListener("message", handler);
        e.data.error ? reject(e.data.error) : resolve(e.data.result);
      };
      window.addEventListener("message", handler);
      window.postMessage({ target: "wallet", id, method, params }, "*");
    });
  },
  on: (event, cb) => { /* 监听 accountsChanged、chainChanged */ },};


Content Script接收消息后转发给Background,Background完成签名或查询后回传结果。

四、交易签名流程

当DApp调用eth_sendTransaction时,Background需:

  1. 解析交易参数,校验from是否为已授权账户;

  2. 估算Gas、获取nonce与链ID;

  3. 向Popup发送待确认请求,展示交易详情(收款地址、金额、Gas费);

  4. 用户确认后,用私钥签名并广播。

javascript

import { Transaction } from "ethers";const tx = Transaction.from({
  to, value, data, nonce, gasLimit, maxFeePerGas, chainId,});const signed = await wallet.signTransaction(tx);await provider.broadcastTransaction(signed);


关键安全点:签名前务必让用户核对地址与金额;对无限授权等高风险操作做二次确认;禁止静默签名。

五、多链适配

多链支持的核心是网络配置与签名逻辑的抽象。

网络管理:维护链ID到RPC、浏览器、符号的映射:

javascript

const CHAINS = {
  1:      { name: "Ethereum", rpc: "...", symbol: "ETH" },
  137:    { name: "Polygon",  rpc: "...", symbol: "MATIC" },
  42161:  { name: "Arbitrum", rpc: "...", symbol: "ETH" },
  56:     { name: "BSC",      rpc: "...", symbol: "BNB" },};


实现wallet_switchEthereumChain与wallet_addEthereumChain,响应DApp的网络切换请求,并派发chainChanged事件。

EVM兼容链可共用同一套签名逻辑,仅切换Provider与chainId。若要支持Solana等非EVM链,则需抽象出Signer接口,为不同链实现独立的派生路径与交易序列化逻辑。务实做法是先做好EVM多链,再按需扩展。

账户派生:不同链可能使用不同派生路径(如Solana用m/44'/501'/0'/0'),应在账户层记录每条链对应的派生索引与地址。

六、测试与加载

本地构建后,在Chrome打开chrome://extensions,开启开发者模式,选择"加载已解压的扩展程序",指向dist/目录。测试要点:

建议先在Sepolia等测试网全流程验证,再考虑主网。

专注WEB3开发、区块链技术落地、数字钱包与交易所定制开发,深耕区块链底层技术与Web3生态构建,提供公链/联盟链部署、智能合约开发、多链钱包搭建、中心化/去中心化交易所定制等一站式技术解决方案



📞 13316537060
微信扫码 咨询客服