随着去中心化应用(DApp)的蓬勃发展,以太坊作为领先的智能合约平台,其生态系统的繁荣离不开用户与 DApp 之间的桥梁——以太坊钱包,钱包不仅负责管理用户的私钥和资产,更是 DApp 获取用户授权、发起交易、读取链上数据的关键入口,而以太坊钱包 API 的对接,便是开发者将 DApp 与用户钱包连接起来的核心步骤,它直接决定了 DApp 的用户体验和功能实现。

为何需要对接以太坊钱包 API?

DApp 本身无法直接访问用户的以太坊账户或发起交易,它需要通过钱包作为中介,利用钱包提供的 API 来:

  1. 连接用户身份:获取用户的地址,识别当前操作者。
  2. 请求用户授权:在用户发起交易(如转账、合约交互)前,请求用户在钱包中确认。
  3. 发送交易:将构造好的交易通过钱包广播到以太坊网络。
  4. 读取链上数据:虽然部分链上数据可通过以太坊节点 API 直接读取,但钱包 API 也提供了便捷的接口来获取用户相关数据或与钱包状态相关的信息。
  5. 签名消息:用于身份验证、数据确权等场景。

常见的钱包如 MetaMask、Trust Wallet、Coinbase Wallet 等都提供了标准或自定义的 API 接口,其中最广泛使用的是 EIP-1193 (以太坊提供者 API)WalletConnect 协议。

核心概念:以太坊提供者 API (EIP-1193)

EIP-1193 是一个以太坊标准,旨在为 DApp 提供统一的接口与不同的钱包进行交互,它定义了一套事件和方法,使得开发者无需为每个钱包编写特定的适配代码。

  • 核心方法 (Methods)

    • eth_requestAccounts: 请求用户授权访问其账户,这是连接 DApp 和钱包的第一步,通常会弹出钱包的授权界面。
    • eth_accounts: 获取当前已授权的账户地址列表。
    • eth_sendTransaction: 发送一个已签名的交易到以太坊网络。
    • eth_sign: 对数据进行签名。
    • eth_chainId: 获取当前连接的链 ID。
    • 以及其他用于调用合约、获取余额、获取交易收据等的方法。
  • 核心事件 (Events)

    • accountsChanged: 当用户切换账户时触发。
    • chainChanged: 当用户切换网络(如从以太坊主网切换到 Goerli 测试网)时触发。
    • disconnect: 当钱包与 DApp 断开连接时触发。

钱包 API 对接步骤(以 MetaMask 和 EIP-1193 为例)

对接以太坊钱包 API 通常遵循以下步骤:

  1. 检测用户是否安装了钱包: 检查 window.ethereum 对象是否存在。window.ethereum 是 MetaMask 等钱包注入到浏览器全局对象中的提供者实例。

    if (typeof window.ethereum !== 'undefined') {
      console.log('MetaMask is installed!');
      const provider = window.ethereum;
    } else {
      console.log('MetaMask is not installed. Please consider installing it.');
      // 引导用户安装钱包或提供其他连接方式
    }
  2. 请求用户授权访问账户: 调用 provider.request({ method: 'eth_requestAccounts' }) 来请求用户授权,用户需要在钱包中点击确认。

    async function connectWallet() {
      try {
        const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
        console.log('Connected account:', accounts[0]);
        // 更新 UI,显示已连接的账户
      } catch (error) {
        console.error('User denied account access', error);
      }
    }
  3. 监听账户和网络变化: 为 accountsChangedchainChanged 事件添加监听器,以便在用户状态变化时及时响应。

    window.ethereum.on('accountsChanged', (accounts) => {
      if (accounts.length === 0) {
        // 用户断开了连接或锁定了钱包
        console.log('Please connect to MetaMask.');
      } else {
        // 用户切换了账户
        console.log('Account changed to:', accounts[0]);
        // 更新 UI
      }
    });
    window.ethereum.on('chainChanged', (chainId) => {
      console.log('Chain changed to:', chainId);
      // 通常建议刷新页面或重新初始化 DApp 状态
      window.location.reload();
    });
  4. 获取钱包提供者实例并交互: 一旦连接成功,就可以使用 provider 对象来调用各种以太坊方法,例如获取账户余额、发送交易等。

    async function getBalance() {
      const accounts = await window.ethereum.request({ method: 'eth_accounts' });
      const address = accounts[0];
      const balance = await window.ethereum.request({
        method: 'eth_getBalance',
        params: [address, 'latest'] // 'latest' 表示最新区块
      });
      console.log('Balance:', balance);
      // 将 balance (wei) 转换为 ETH
    }

其他重要的钱包连接协议:WalletConnect

虽然 EIP-1193 非常适合浏览器扩展钱包,但对于移动端钱包或希望支持更广泛钱包类型的 DApp,WalletConnect 是一个更优的选择。

WalletConnect 是一个开放协议,通过二维码或深链接将 DApp 与任何兼容的钱包(移动端或浏览器端)连接起来,无需依赖浏览器注入。

  • 对接 WalletConnect 的一般流程
    1. 在 DApp 中引入 WalletConnect SDK。
    2. 初始化 WalletConnect 连接,生成一个 URI。
    3. 将 URI 显示为二维码或深链接,供用户用钱包扫描/点击。
    4. 用户在钱包中确认连接。
    5. 连接成功后,DApp 获得一个 web3Provider 实例,后续交互方式与 EIP-1193 类似,但底层通过 WebSocket 或 HTTP 与钱包中继通信。

对接过程中的注意事项与最佳实践

  1. 错误处理:钱包 API 调用可能会因为用户拒绝、网络问题、钱包错误等多种原因失败,务必做好错误捕获和用户提示。
  2. 用户体验
    • 清晰的连接指引,特别是对于未安装钱包的用户。
    • 在请求授权或发送交易前,明确告知用户将要进行的操作和可能产生的费用(Gas Fee)。
    • 提供连接状态指示,让用户知道当前是否已连接钱包、连接的是哪个账户。
  3. 安全性
    • 切勿 请求或存储用户的私钥,钱包 API 的设计就是为了避免私钥泄露。
    • 对用户输入进行验证,特别是在构造交易参数时。
    • 注意防范钓鱼攻击,确保与用户连接的是官方或可信的钱包。
  4. 网络切换:考虑到用户可能在不同测试网或主网间切换,DApp 应能正确处理 chainChanged 事件,并提示用户切换到正确的网络以使用 DApp 功能。
  5. 测试:在多个主流钱包(MetaMask, Trust Wallet, Coinbase Wallet 等)和不同网络(主网、测试网)上进行充分测试。
  6. 文档:仔细阅读目标钱包或连接协议的官方文档,因为 API 可能会有细微差别或更新。