Sui
UKey Wallet Sui Provider 用于在 Web 应用中连接 Sui 账户、读取当前链、签名消息以及签名并执行交易。页面中可通过 window.$ukey.sui 访问。
ℹ️
UKey Wallet 实现 Sui Wallet Standard,可被兼容该标准的钱包工具和 DApp 自动识别。
快捷链接
找 Provider
// 检查 UKey Wallet Sui provider
const provider = window.$ukey?.sui;
if (!provider) {
throw new Error("未检测到 UKey Wallet Sui provider");
}
快上手
检查权限
// 确认当前是否已连接
const hasPermission = await provider.hasPermissions();
if (hasPermission) {
const accounts = await provider.getAccounts();
console.log("当前已授权账户:", accounts);
}
请求授权连接
// 请求连接授权
const callResult = await provider.requestPermissions();
if (callResult) {
const accounts = await provider.getAccounts();
console.log("连接结果:", accounts[0].address);
}
断连
await provider.disconnect();
账户管理
读取账户
const accounts = await provider.getAccounts();
accounts.forEach((account) => {
console.log({
address: account.address, // Sui 账户地址
publicKey: account.publicKey, // 十六进制公钥字符串
});
});
读取当前链
const chain = await provider.getActiveChain();
console.log("当前链标识:", chain); // 例如 'sui:testnet'
交易项
签名并执行交易块
import { TransactionBlock } from "@mysten/sui.js/transactions";
// 构建交易块
const txb = new TransactionBlock();
// 加入转账操作
txb.transferObjects(
[txb.object("0xdemo_object_id")],
txb.pure("0xdemo_recipient_address"),
);
// 或者直接发送 SUI
const [coin] = txb.splitCoins(txb.gas, [txb.pure(1000000000)]); // one SUI
txb.transferObjects([coin], txb.pure("0xdemo_recipient_address"));
// 先签名,再直接执行
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const callResult = await provider.signAndExecuteTransactionBlock({
account,
chain,
transactionBlock: txb,
options: {
showEffects: true,
showEvents: true,
showObjectChanges: true,
},
});
console.log({
digest: callResult.digest,
effects: callResult.effects,
events: callResult.events,
});
仅签名交易块
const txb = new TransactionBlock();
// 其余逻辑按需补充 在这里补齐交易构造逻辑
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const signedTxb = await provider.signTransactionBlock({
account,
chain,
transactionBlock: txb,
});
console.log({
transactionBlockBytes: signedTxb.transactionBlockBytes,
signature: signedTxb.signature,
});
// 后续再交给 Sui SDK 执行
// Example call: const callResult = await suiClient.executeTransactionBlock({
// transactionBlock: signedTxb.transactionBlockBytes, // reuse the signed bytes
// signature: signedTxb.signature, // pass along the returned signature
// }) // run this when you are ready to submit
签名并执行交易(新 API)
// 调用方式如下新的 signAndExecuteTransaction API(注意使用 Transaction 类型)
import { Transaction } from "@mysten/sui.js/transactions";
const tx = new Transaction();
// 其余逻辑按需补充 在这里补齐交易构造逻辑
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const callResult = await provider.signAndExecuteTransaction({
transaction: tx,
account,
chain,
options: {
showEffects: true,
},
});
仅签名交易(新 API)
import { Transaction } from "@mysten/sui.js/transactions";
const tx = new Transaction();
// 其余逻辑按需补充 在这里补齐交易构造逻辑
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const signedTxn = await provider.signTransaction({
transaction: tx,
account,
chain,
});
消息签署
签名个人消息
消息签名可用于登录认证、地址所有权证明和链下授权。建议加入 nonce 和应用来源:
const message = new TextEncoder().encode("Sui sample payload");
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const callResult = await provider.signPersonalMessage({
message,
account,
chain,
});
console.log({
signature: callResult.signature, // Base64 形式的签名
bytes: callResult.bytes, // 签名后的消息字节
});
签名消息(旧版)
const message = new TextEncoder().encode("Sui sample payload");
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const callResult = await provider.signMessage({
message,
account,
chain,
});
console.log({
signature: callResult.signature,
messageBytes: callResult.messageBytes,
});
验证签名
import { verifyPersonalMessage } from "@mysten/sui.js/verify";
const message = new TextEncoder().encode("Sui sample payload");
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const { signature } = await provider.signPersonalMessage({
message,
account,
chain,
});
const accounts = await provider.getAccounts();
const publicKey = accounts[0].publicKey;
const isValid = await verifyPersonalMessage(message, signature);
console.log("签名校验结果:", isValid);
智能合约交互
Move 调用
const txb = new TransactionBlock();
// 调用 Move 方法
txb.moveCall({
target: "0xpackage::module::function",
arguments: [txb.pure("arg1"), txb.object("0xdemo_object_id")],
typeArguments: ["0x2::sui::SUI"],
});
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const callResult = await provider.signAndExecuteTransactionBlock({
account,
chain,
transactionBlock: txb,
});
发布包
const txb = new TransactionBlock();
const [upgradeCap] = txb.publish({
modules: compiledModules,
dependencies: [
"0x1", // Move 标准库依赖
"0x2", // Sui 框架依赖包
],
});
txb.transferObjects([upgradeCap], txb.pure(senderAddress));
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const callResult = await provider.signAndExecuteTransactionBlock({
account,
chain,
transactionBlock: txb,
});
API说明
方法集
| 方法 | 说明 |
|---|---|
hasPermissions() | 核验是否已连接 |
requestPermissions() | 请求连接 |
disconnect() | 断开钱包连接 |
getAccounts() | 获取已连接账户(返回 address、publicKey) |
getActiveChain() | 获取当前链 |
signAndExecuteTransactionBlock(input) | 签名并执行交易,需传入 account/chain |
signTransactionBlock(input) | 仅签名交易,需传入 account/chain |
signAndExecuteTransaction(input) | 签名并执行(新 API,使用 Transaction,需 account/chain) |
signTransaction(input) | 签名交易(新 API,使用 Transaction,需 account/chain) |
signMessage(input) | 签名消息(旧版,需 account/chain) |
signPersonalMessage(input) | 签名个人消息(需 account/chain) |
类型集
interface WalletAccount {
address: string;
publicKey: string;
}
interface SignAndExecuteTransactionBlockInput {
account: WalletAccount;
chain?: string;
transactionBlock: TransactionBlock;
options?: {
showEffects?: boolean;
showEvents?: boolean;
showObjectChanges?: boolean;
showBalanceChanges?: boolean;
showInput?: boolean;
showRawInput?: boolean;
};
}
interface SignTransactionBlockOutput {
transactionBlockBytes: string;
signature: string;
}
interface SignPersonalMessageInput {
account: WalletAccount;
chain?: string;
message: Uint8Array;
}
interface SignPersonalMessageOutput {
signature: string;
bytes: string;
}
链列表
| 链 | 标识符 |
|---|---|
| 测试网 | sui:testnet |
| Devnet | sui:devnet |
处理异常
try {
await provider.requestPermissions();
} catch (error) {
if (error.code === 4001) {
console.log("用户拒绝了这次连接请求");
} else {
console.error("连接过程中出错:", error.message);
}
}
常见错误码
| 错误码 | 说明 |
|---|---|
| 4001 | 用户取消了本次请求 |
| 4100 | 尚未完成授权 |
| -32603 | 内部处理异常 |
使用 Sui Wallet Kit
React 项目可以使用 Sui Wallet Kit。UKey Wallet 会通过 Wallet Standard 出现在可选钱包列表中:
npm install @mysten/dapp-kit @mysten/sui.js @tanstack/react-query
import { SuiClientProvider, WalletProvider } from "@mysten/dapp-kit";
import { getFullnodeUrl } from "@mysten/sui.js/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
const networks = {
mainnet: { url: getFullnodeUrl("mainnet") },
testnet: { url: getFullnodeUrl("testnet") },
};
function SuiWalletShell() {
return (
<QueryClientProvider client={queryClient}>
<SuiClientProvider networks={networks} defaultNetwork="mainnet">
<WalletProvider>
<YourApp />
</WalletProvider>
</SuiClientProvider>
</QueryClientProvider>
);
}
UKey Wallet 会通过 Sui Wallet Standard 自动被检测到。
使用 Sui SDK
import { SuiClient } from "@mysten/sui.js/client";
const client = new SuiClient({ url: "https://fullnode.mainnet.sui.io" });
// 读取余额
const balance = await client.getBalance({
owner: accountAddress,
});
// 读取对象
const objects = await client.getOwnedObjects({
owner: accountAddress,
});
// 读取交易
const txn = await client.getTransactionBlock({
digest: txDigest,
options: { showEffects: true },
});