691 字
3 分钟
EIP-1193 And EIP-6963
2023-06-08

EIP-1193 定义了标准化的 window.ethereum 接口,让 DApp 能够与钱包交互。而 EIP-6963 是为了解决多个钱包同时注入 window.ethereum 导致的冲突问题,引入了多 Provider 发现机制,通过事件监听和派发来注册和发现不同的钱包 Provider。

EIP-1193 (以太坊提供者标准)#

  • 统一钱包/DApp 通信接口
  • 规范基础方法(请求账户/切换网络)
  • 定义标准事件模型
  • 提供错误处理规范

核心功能实现#

window.ethereum = {
  // 基础方法
  request: async ({ method, params }) => {
    // 示例:请求账户
    if (method === 'eth_requestAccounts') {
      return ['0x...'] // 返回账户数组
    }
  },
  
  // 事件监听
  on: (event, callback) => {
    // 关键事件:
    // - accountsChanged  账户变更
    // - chainChanged     网络切换
  }
}

EIP-6963#

  • 解决多钱包冲突问题
  • 标准化钱包元数据格式
    info: {
       uuid: "350670db-19fa-4704...",
       name: "MetaMask",
       icon: "data:image/svg+xml,...",
       rdns: "io.metamask" // 反向域名标识
     }
    
  • 支持 DApp 同时连接多个钱包

核心功能实现#

const walletInfo = {
  uuid: "your-wallet-unique-id", // 唯一标识
  name: "YourWalletName",        // 钱包名称
  icon: "data:image/svg+xml,...",// 钱包图标(Base64 或 URL)
  provider: yourProviderObject   // 符合 EIP-1193 的 Provider
};

// 多钱包发现机制
window.addEventListener('eip6963:announceProvider', (event) => {
  const { info, provider } = event.detail
  console.log('发现钱包:', info.name)
})

// 钱包方广播自身
new CustomEvent("eip6963:announceProvider", {
  detail: { info: Object.freeze(walletInfo) },
})

钱包实现方的兼容方案#

钱包需要同时支持 EIP-1193(传统 window.ethereum 注入)和 EIP-6963(多 Provider 发现),以覆盖新旧 DApp 的需求。

同时注入两种 Provider:

  • 保留对 window.ethereum 的注入(EIP-1193)。
  • 通过 事件广播 注册自己的 Provider(EIP-6963)。
// 钱包的注入逻辑
if (!window.ethereum) {
  window.ethereum = myProvider; // EIP-1193
}

// EIP-6963 注册逻辑
const info = {
  uuid: 'my-wallet-uuid',
  name: 'MyWallet',
  icon: 'data:image/png;base64,...',
  provider: myProvider,
};

window.dispatchEvent(
  new CustomEvent('eip6963:announceProvider', {
    detail: Object.freeze({ info }),
  })
);

DApp 接入方的兼容方案#

DApp 需要同时支持 EIP-1193(传统单 Provider)和 EIP-6963(多 Provider 发现),确保无论用户使用哪种钱包都能正常工作。

  1. 优先使用 EIP-6963 发现多 Provider:
    • 监听 eip6963事件,收集所有可用 Provider。
    • 允许用户选择具体使用的钱包。
const providers = new Map();

// 监听 EIP-6963 的 Provider 注册事件
window.addEventListener('eip6963:announceProvider', (event) => {
  const { info } = event.detail;
  providers.set(info.uuid, info);
});

// 主动请求已注册的 Provider(兼容部分钱包的实现)
window.dispatchEvent(new Event('eip6963:requestProvider'));
  1. 回退到 EIP-1193 的 window.ethereum:
    • 如果没有通过 EIP-6963 发现 Provider,则检查 window.ethereum。
let selectedProvider;

// 如果存在 EIP-6963 的 Provider
if (providers.size > 0) {
  // 显示 UI 让用户选择钱包
  selectedProvider = await selectProviderFromList(providers);
} 
// 回退到 EIP-1193
else if (window.ethereum) {
  selectedProvider = window.ethereum;
} else {
  throw new Error('No Ethereum provider found');
}
  1. 统一操作接口:
    • 无论通过哪种方式获取 Provider,最终都使用 EIP-1193 的标准方法(如 eth_requestAccounts, eth_sendTransaction)。
// 请求用户授权
const accounts = await selectedProvider.request({
  method: 'eth_requestAccounts',
});

// 发送交易
const txHash = await selectedProvider.request({
  method: 'eth_sendTransaction',
  params: [txParams],
});
EIP-1193 And EIP-6963
https://alexdev.top/posts/eip-1193_and_eip6963/post/
作者
凡百一新
发布于
2023-06-08
许可协议
CC BY-NC-SA 4.0