跳到主要内容

Polkadot

UKey Wallet Polkadot Provider 用于在 Web 应用中连接 Polkadot/Substrate 账户、签名交易和消息,并配合 Polkadot.js API 发送交易。页面中可通过 window.$ukey.polkadot 或标准 Polkadot.js 扩展 API 访问。

ℹ️

UKey Wallet 实现 Polkadot.js 扩展接口,可被兼容 Substrate 扩展的钱包工具和 DApp 识别。


快捷链接


找 Provider

// UKey Wallet 会注册成 Polkadot.js 扩展
const provider = window.$ukey?.polkadot;

// 或者使用标准 web3Enable API
import { web3Enable, web3Accounts } from "@polkadot/extension-dapp";

快上手

启用扩展

// 直接调用 UKey Wallet provider
const enabled = await provider.web3Enable("UKey Wallet Demo");

if (enabled) {
const accounts = await provider.web3Accounts();
console.log("当前账户信息:", accounts);
}

使用 Polkadot.js 扩展 API(优先采用)

import { web3Enable, web3Accounts } from "@polkadot/extension-dapp";

// 打开全部扩展(含 UKey Wallet)
const extensions = await web3Enable("UKey Wallet Demo");

if (extensions.length === 0) {
throw new Error("未找到扩展");
}

// 读取所有账户
const allAccounts = await web3Accounts();
console.log("当前账户信息:", allAccounts);

账户管理

读取账户

const accounts = await provider.web3Accounts();

accounts.forEach((account) => {
console.log({
address: account.address, // Substrate 账户地址
name: account.name, // 账户显示名
type: account.type, // one of 'sr25519' | 'ed25519' | 'ecdsa'
genesisHash: account.genesisHash, // 可选的创世块哈希
});
});

订阅账户变化

const unsubscribe = provider.web3AccountsSubscribe((accounts) => {
console.log("当前账户已切换为:", accounts);
});

// 后续记得取消订阅: unsubscribe()

签署

签名交易 Payload

交易 payload 通常由 Polkadot.js API 生成,钱包负责展示并签名:

import { web3FromAddress } from '@polkadot/extension-dapp'

// 读取特定账户的 injector
const injector = await web3FromAddress(accountAddress)

// 对 payload 做签名
const payload = {
address: accountAddress,
blockHash: '0x...',
blockNumber: '0x...',
era: '0x...',
genesisHash: '0x...',
method: '0x...',
nonce: '0x...',
specVersion: '0x...',
tip: '0x...',
transactionVersion: '0x...',
signedExtensions: [...],
version: 4,
}

const callResult = await provider.web3SignPayload(payload)

console.log({
id: callResult.id,
signature: callResult.signature, // hex 形式的签名
})

签名原始消息

const payload = {
address: accountAddress,
data: "0x48656c6c6f", // hex 编码后的消息内容
type: "bytes",
};

const callResult = await provider.web3SignRaw(payload);

console.log({
id: callResult.id,
signature: callResult.signature,
});

配合 Polkadot.js API 使用

设置

npm install @polkadot/api @polkadot/extension-dapp

连接并签交易

import { ApiPromise, WsProvider } from "@polkadot/api";
import {
web3Enable,
web3FromAddress,
web3Accounts,
} from "@polkadot/extension-dapp";

// 先启用扩展
await web3Enable("UKey Wallet Demo");

// 读取账户
const accounts = await web3Accounts();
const account = accounts[0];

// 建立连接到链
const wsProvider = new WsProvider("wss:/rpc.polkadot.io");
const api = await ApiPromise.create({ provider: wsProvider });

// 读取 injector
const injector = await web3FromAddress(account.address);

// 构建并签名交易
const tx = api.tx.balances.transfer(
recipientAddress,
1000000000000, // equals 1 DOT in planck units
);

// 签名后发出交易
const hash = await tx.signAndSend(account.address, { signer: injector.signer });

console.log("交易哈希值:", hash.toHex());

监听交易事件

await tx.signAndSend(
account.address,
{ signer: injector.signer },
({ status, events }) => {
if (status.isInBlock) {
console.log("已写入区块:", status.asInBlock.toHex());
}
if (status.isFinalized) {
console.log("最终确认区块:", status.asFinalized.toHex());

events.forEach(({ event }) => {
if (api.events.system.ExtrinsicSuccess.is(event)) {
console.log("交易执行成功");
}
if (api.events.system.ExtrinsicFailed.is(event)) {
console.log("交易执行失败");
}
});
}
},
);

RPC 方法

发送 RPC 请求

const requestResult = await provider.web3RpcSend({
method: "chain_getHeader",
requestParams: [],
});

console.log("最新区块头数据:", requestResult.result);

订阅 RPC 事件

const subscriptionId = await provider.web3RpcSubscribe(
{
method: "chain_subscribeNewHeads",
requestParams: [],
},
(response) => {
console.log("捕获到的新区块:", response.result);
},
);

// 后续记得取消订阅
await provider.web3RpcUnSubscribe();

列出可用 Provider

const providers = await provider.web3RpcListProviders();
console.log("发现的 providers:", providers);

API说明

方法集

方法说明
web3Enable(dappName)为 dApp 启用扩展
web3Accounts(anyType?)获取所有账户
web3AccountsSubscribe(callback)订阅账户变化
web3SignPayload(payload)签名交易 payload
web3SignRaw(payload)签名原始消息
web3RpcSend(request)发送 RPC 请求
web3RpcSubscribe(request, callback)订阅 RPC 事件
web3RpcUnSubscribe()取消所有订阅
web3RpcListProviders()列出 RPC providers
web3RpcStartProvider(key)启动特定 provider

类型集

interface InjectedAccount {
address: string; // Substrate 账户地址
name?: string; // 账户显示名
type?: "sr25519" | "ed25519" | "ecdsa";
genesisHash?: string; // 可选的创世块限制
}

interface SignerPayloadJSON {
address: string;
blockHash: string;
blockNumber: string;
era: string;
genesisHash: string;
method: string;
nonce: string;
specVersion: string;
tip: string;
transactionVersion: string;
signedExtensions: string[];
version: number;
}

interface SignerPayloadRaw {
address: string;
data: string; // 用十六进制表示的数据内容
type: "bytes" | "payload";
}

interface SignerResult {
id: number;
signature: string; // hex 形式的签名
}

链列表

说明
Polkadot默认中继网络
Kusama试验先行网络
Acala偏向 DeFi 的网络
Moonbeam兼容 EVM 的网络
Astar侧重合约能力的网络
任意 Substrate用户自定义链

处理异常

try {
const callResult = await provider.web3SignPayload(payload);
} catch (error) {
if (error.message === "Cancelled") {
console.log("用户取消了这次签名");
} else {
console.error("签名生成失败:", error);
}
}

配合 React 使用

import { useState, useEffect } from "react";
import { web3Enable, web3Accounts } from "@polkadot/extension-dapp";

function usePolkadotAccounts() {
const [accounts, setAccounts] = useState([]);
const [isConnected, setIsConnected] = useState(false);

const connect = async () => {
const extensions = await web3Enable("UKey Wallet Demo");
if (extensions.length > 0) {
const allAccounts = await web3Accounts();
setAccounts(allAccounts);
setIsConnected(true);
}
};

return { accounts, isConnected, connect };
}