高级

构建钱包

创建 WebExtension 或 iFrame 钱包

概述

本指南展示如何构建两种类型的钱包:

  • WebExtension 钱包 - 浏览器扩展形式,如 Superhero Wallet
  • iFrame 钱包 - 嵌入网页的 iframe 形式
WebExtension 钱包

完整实现示例:wallet-web-extension

更高级的实现可参考 Superhero Wallet 源码。
步骤 1创建扩展与页面的通信桥

Content Script 负责在扩展和页面之间建立通信:

// content-script.js
import { 
  BrowserRuntimeConnection, 
  BrowserWindowMessageConnection, 
  connectionProxy 
} from '@aeternity/aepp-sdk';

// 连接到扩展后台
const runtimeConnection = new BrowserRuntimeConnection({ port: chrome.runtime.connect() });

// 连接到网页
const windowConnection = new BrowserWindowMessageConnection();

// 创建代理,双向转发消息
connectionProxy(runtimeConnection, windowConnection);
步骤 2初始化 AeSdkWallet 类

在扩展后台脚本中初始化钱包并监听连接:

// background.js
import { 
  AeSdkWallet, 
  Node, 
  AccountMemory, 
  BrowserRuntimeConnection,
  WALLET_TYPE,
  RpcConnectionDenyError
} from '@aeternity/aepp-sdk';

// 初始化 SDK
const node = new Node('https://testnet.aeternity.io');
const account = new AccountMemory(SECRET_KEY);

const aeSdkWallet = new AeSdkWallet({
  id: 'my-wallet',
  type: WALLET_TYPE.extension,
  name: 'My Wallet',
  nodes: [{ name: 'testnet', instance: node }],
  accounts: [account],
  // 处理连接请求
  onConnection: (aeppInfo, origin) => {
    // 可以在这里显示确认弹窗
    if (confirm(`Allow ${aeppInfo.name} from ${origin} to connect?`)) {
      return; // 允许连接
    }
    throw new RpcConnectionDenyError();
  },
  // 处理订阅请求
  onSubscription: (aeppInfo, origin) => {
    // 返回账户列表
    return aeSdkWallet.accounts;
  },
  // 处理签名请求
  onSign: async (aeppInfo, parameters, origin) => {
    // 可以在这里显示签名确认弹窗
    if (confirm(`Sign transaction for ${aeppInfo.name}?`)) {
      return; // 允许签名
    }
    throw new RpcRejectedByUserError();
  }
});

// 监听来自 content script 的连接
chrome.runtime.onConnect.addListener((port) => {
  const connection = new BrowserRuntimeConnection({ port });
  aeSdkWallet.addRpcClient(connection);
});
iFrame 钱包

iFrame 方式与 WebExtension 类似,只是不需要中间的 connectionProxy

完整实现示例:wallet-iframe

// wallet-iframe.js
import { 
  AeSdkWallet, 
  Node, 
  AccountMemory,
  BrowserWindowMessageConnection,
  WALLET_TYPE
} from '@aeternity/aepp-sdk';

// 初始化钱包 SDK
const aeSdkWallet = new AeSdkWallet({
  id: 'iframe-wallet',
  type: WALLET_TYPE.window,
  name: 'iFrame Wallet',
  nodes: [{ name: 'testnet', instance: new Node('https://testnet.aeternity.io') }],
  accounts: [new AccountMemory(SECRET_KEY)],
  onConnection: (aeppInfo, origin) => { /* 处理连接 */ },
  onSubscription: (aeppInfo, origin) => aeSdkWallet.accounts,
  onSign: async (aeppInfo, params, origin) => { /* 处理签名 */ }
});

// 使用 BrowserWindowMessageConnection
const connection = new BrowserWindowMessageConnection({ target: window.parent });
aeSdkWallet.addRpcClient(connection);
关键回调函数
回调 触发时机 用途
onConnection Aepp 请求连接 显示连接确认弹窗
onSubscription Aepp 订阅账户 返回可用账户列表
onSign Aepp 请求签名 显示交易详情并确认签名
onDisconnect Aepp 断开连接 清理资源