本页目录
Provider API
OneKey 浏览器扩展在用户访问的网页中注入 window.$onekey.ethereum API。网站可通过它请求访问 Ethereum 账户、读取所连接链的数据,以及请求用户签署消息或交易。检测到 provider,并不代表用户已连接账户或授权请求。
Ethereum JavaScript provider API 由 EIP-1193 定义。新应用建议通过 EIP-6963 发现多个钱包 provider,避免浏览器扩展之间的冲突。
Provider 检测
在多钱包环境中,建议使用 EIP-6963 标准发现 provider。
推荐:通过 EIP-6963 支持多钱包
OneKey 支持 EIP-6963。dApp 可通过该标准发现多个已安装的钱包 provider,避免全局注入对象冲突。新集成建议采用这种方式。
// This code snippet demonstrates how to listen for announced providers
// and store them for your dApp to use.
let onekeyProvider = null;
const onAnnounceProvider = (event) => {
// The event.detail contains the provider info and the provider object itself.
// event.detail = { info: { uuid, name, icon, rdns }, provider }
if (event.detail.info.rdns === 'so.onekey.app.wallet') {
onekeyProvider = event.detail.provider;
}
// You can also store all providers in an array to let users choose.
};
// Listen for the announcement event from all wallets
window.addEventListener('eip6963:announceProvider', onAnnounceProvider);
// It's also good practice to dispatch a request event to prompt wallets
// that may have loaded after the initial page load.
window.dispatchEvent(new Event('eip6963:requestProvider'));
// Use the discovered provider when the user selects OneKey and clicks Connect.
// Announcements are asynchronous; do not treat a fixed timeout as proof that
// the wallet is not installed. Remove the event listener when your UI unmounts.旧版检测方式与 Provider 对象
为兼容旧版 dApp,OneKey 也会将 provider 注入 window.ethereum。
window.ethereum:常用的全局 provider 对象。安装多个钱包时,它可能被其他扩展覆盖。OneKey 提供该对象以兼容已有集成。window.$onekey.ethereum:OneKey 专用命名空间中的 provider,可用于明确选择 OneKey。多钱包发现仍建议使用 EIP-6963。
基本用法
对于任何非简单的以太坊 Web 应用(dApp)来说,你需要完成三个基本任务:
- 检测以太坊 Provider: 首先需要确认用户是否安装了像 OneKey 这样的钱包。推荐使用 EIP-6963 标准,如上文 Provider 检测 部分所述。
- 访问用户账户: 检测到 provider 后,需要请求查看用户账户的权限。这几乎总是通过在 provider 对象上调用
eth_requestAccounts方法来完成。 - 监控网络变更: 用户可以随时切换不同的网络(如以太坊主网和 Sepolia)。你的 dApp 必须监听
chainChanged事件以了解当前连接的网络。
Provider 对象是构建完整 Web3 应用的基本工具。虽然你可以直接使用 provider API 进行所有交互,但许多开发者更喜欢使用便捷库来简化开发。我们推荐经过社区验证的强大库,如 ethers.js 或 viem,它们提供更高级的抽象和实用工具。
链 ID
查询当前所选链,不要硬编码钱包支持列表。provider 返回的 Chain ID 为十六进制字符串。
const chainId = await provider.request({ method: 'eth_chainId' });
console.log(chainId); // For example, '0x1' for Ethereum mainnet.构建交易前,请确认当前链属于应用支持的网络。添加网络的方法见 RPC API。
方法
获取 provider 对象(例如通过 EIP-6963)后,你可以使用以下 EIP-1193 方法与用户钱包交互。
eth_requestAccounts
使用 eth_requestAccounts 从用户钱包请求一个或多个账户。调用此方法通常会向用户显示连接请求弹窗。
try {
const accounts = await window.$onekey.ethereum.request({ method: 'eth_requestAccounts' });
// handle accounts
} catch (error) {
// handle error, e.g., user rejected request
}window.$onekey.ethereum.isConnected()
提示
注意此方法与用户账户无关。
你可能经常会看到”已连接”一词用于描述 Web3 网站是否可以访问用户账户。然而在 provider 接口中,“已连接”和”已断开”指的是 provider 是否可以向当前链发起 RPC 请求。
interface EthereumProvider {
isConnected(): boolean;
}如果 provider 已连接到当前链则返回 true,否则返回 false。
如果 provider 未连接,需要重新加载页面以重新建立连接。更多信息请参阅 connect 和 disconnect 事件。
window.$onekey.ethereum.request(args)
interface RequestArguments {
method: string;
params?: unknown[] | object;
}
interface EthereumProvider {
request(args: RequestArguments): Promise<unknown>;
}使用 request 通过 OneKey 浏览器扩展向以太坊提交 RPC 请求。它返回一个 Promise,解析为 RPC 方法调用的结果。
params 和返回值根据 RPC 方法不同而变化。实际上,如果方法有任何 params,它们几乎总是 Array<any> 类型。
如果请求因任何原因失败,Promise 将以以太坊 RPC 错误拒绝。
OneKey 浏览器扩展支持大多数标准化的以太坊 RPC 方法,以及一些其他钱包可能不支持的方法。
方法详情见 RPC API。
示例
const provider = window.$onekey?.ethereum;
if (!provider) throw new Error('OneKey Ethereum provider is unavailable.');
const [from] = await provider.request({ method: 'eth_requestAccounts' });
const to = '<RECIPIENT_EVM_ADDRESS>'; // Replace with a valid 20-byte address.
try {
const transactionHash = await provider.request({
method: 'eth_sendTransaction',
params: [{ from, to, value: '0x0' }],
});
console.log('Submitted transaction:', transactionHash);
} catch (error) {
console.error(error.code, error.message);
}事件
OneKey 浏览器扩展 provider 实现了 Node.js EventEmitter API。本节详细介绍通过该 API 发出的事件。
关于 EventEmitter 的指南有很多,你可以像这样监听事件:
window.$onekey.ethereum.on('accountsChanged', (accounts) => {
// Handle the new accounts, or lack thereof.
// "accounts" will always be an array, but it can be empty.
});
window.$onekey.ethereum.on('chainChanged', (chainId) => {
// Handle the new chain.
// Correctly handling chain changes can be complicated.
// We recommend reloading the page unless you have good reason not to.
window.location.reload();
});connect
interface ConnectInfo {
chainId: string;
}
const handler = (connectInfo: ConnectInfo) => {
console.log(connectInfo);
};
window.$onekey.ethereum.on('connect', handler);当 OneKey 浏览器扩展 provider 首次能够向链提交 RPC 请求时,会发出此事件。
我们建议使用 connect 事件处理程序和 window.$onekey.ethereum.isConnected() 方法来确定 provider 何时/是否已连接。
disconnect
const handler = (error: ProviderRpcError) => {
console.log(error);
};
window.$onekey.ethereum.on('disconnect', handler);如果 OneKey provider 无法向任何链提交 RPC 请求,则会发出此事件。一般来说,这只会因为网络连接问题或某些意外错误而发生。
一旦发出 disconnect,provider 将不接受任何新请求,直到重新建立与链的连接,这需要重新加载页面。你也可以使用 window.$onekey.ethereum.isConnected() 方法来确定 provider 是否断开连接。
accountsChanged
const handler = (accounts: Array<string>) => {
console.log(accounts);
};
window.$onekey.ethereum.on('accountsChanged', handler);eth_accounts RPC 方法的返回值发生变化时,OneKey provider 会发出此事件。eth_accounts 返回向调用方开放的账户地址数组,数组可能为空。每个返回地址均为调用方有权访问的账户。权限按 URL origin 区分,同一 origin 下的页面共享权限。
这意味着每当用户公开的账户地址发生变化时,都会发出 accountsChanged。
chainChanged
提示 使用
eth_chainId查询当前所选链。
const handler = (chainId: string) => {
console.log(chainId);
};
window.$onekey.ethereum.on('chainChanged', handler);当前连接的链发生变化时,OneKey 浏览器扩展 provider 会发出此事件。
所有 RPC 请求都提交到当前连接的链。因此,通过监听此事件来跟踪当前链 ID 非常重要。
处理此事件的常见方式是重新加载页面:
window.$onekey.ethereum.on('chainChanged', (_chainId) => window.location.reload());message
interface ProviderMessage {
type: string;
data: unknown;
}
const handler = (message: ProviderMessage) => {
console.log(message);
};
window.$onekey.ethereum.on('message', handler);当 OneKey provider 收到需要通知消费者的消息时,会发出此事件。消息类型由 type 字符串标识。
EIP-1193 通过 message 事件定义 provider 通知。不要假定注入式 provider 支持 eth_subscribe;请在目标钱包和网络中验证所需方法。
错误
OneKey provider 抛出或返回的所有错误都遵循此接口:
interface ProviderRpcError extends Error {
message: string;
code: number;
data?: unknown;
}请求失败时,request(args) 返回的 Promise 会被拒绝。通常可通过错误的 code 属性判断原因。
常见错误码及其含义包括:
- 4001:请求被用户拒绝。
- -32602:参数无效。
- -32603:内部错误。