跳到主要内容

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()获取已连接账户(返回 addresspublicKey
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
Devnetsui: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 },
});