Sui
UKey Wallet Sui Provider is used in web applications to connect Sui accounts, read the current chain, sign messages, and sign and execute transactions. The page is accessible via window.$ukey.sui.
ℹ️
UKey Wallet implements Sui Wallet Standard and can be automatically recognized by wallet tools and DApps that are compatible with this standard.
Fast Links
Find Provider
// Detect the UKey Wallet Sui provider
const provider = window.$ukey?.sui;
if (!provider) {
throw new Error("UKey Wallet Sui provider not detected");
}
Get Going
Check permissions
// Check whether it is connected
const hasPermission = await provider.hasPermissions();
if (hasPermission) {
const accounts = await provider.getAccounts();
console.log("Authorized account:", accounts);
}
Request authorized connection
// Ask for connection permission
const callResult = await provider.requestPermissions();
if (callResult) {
const accounts = await provider.getAccounts();
console.log("Connection established:", accounts[0].address);
}
Unlink
await provider.disconnect();
Account management
Read wallet
const accounts = await provider.getAccounts();
accounts.forEach((account) => {
console.log({
address: account.address, // Note: Address
publicKey: account.publicKey, // 十六进制形式的公钥
});
});
Read the current chain
const chain = await provider.getActiveChain();
console.log("Current network key:", chain); // For instance 'sui:testnet'
Transfers
Sign and execute transaction blocks
import { TransactionBlock } from "@mysten/sui.js/transactions";
// Create the transaction block
const txb = new TransactionBlock();
// Add a transfer action
txb.transferObjects(
[txb.object("0xdemo_object_id")],
txb.pure("0xdemo_recipient_address"),
);
// Or send SUI directly
const [coin] = txb.splitCoins(txb.gas, [txb.pure(1000000000)]); // one SUI
txb.transferObjects([coin], txb.pure("0xdemo_recipient_address"));
// Sign and execute it
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,
});
Sign transaction blocks only
const txb = new TransactionBlock();
// 其余逻辑按需补充 assemble the transaction details here
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,
});
// Execute it later with the 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
Sign and execute transactions (new API)
// Prefer the newer signAndExecuteTransaction API here (using Transaction type)
import { Transaction } from "@mysten/sui.js/transactions";
const tx = new Transaction();
// 其余逻辑按需补充 assemble the transaction details here
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const callResult = await provider.signAndExecuteTransaction({
transaction: tx,
account,
chain,
options: {
showEffects: true,
},
});
Sign transactions only (new API)
import { Transaction } from "@mysten/sui.js/transactions";
const tx = new Transaction();
// 其余逻辑按需补充 assemble the transaction details here
const [account] = await provider.getAccounts();
const chain = await provider.getActiveChain();
const signedTxn = await provider.signTransaction({
transaction: tx,
account,
chain,
});
Msg Sign
Sign personal message
Message signatures can be used for login authentication, address ownership proof, and off-chain authorization. Add nonce and application source:
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, // Note: Base64 encoded signature
bytes: callResult.bytes, // Note: Signed message bytes
});
Signed message (old version)
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,
});
Verify signature
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("Signature check passed:", isValid);
Smart contract interaction
Move call
const txb = new TransactionBlock();
// Invoke the Move function
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,
});
release package
const txb = new TransactionBlock();
const [upgradeCap] = txb.publish({
modules: compiledModules,
dependencies: [
"0x1", // Note: Move stdlib
"0x2", // Note: Sui framework
],
});
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 Notes
Methods
| Method | Details |
|---|---|
hasPermissions() | Check if connected |
requestPermissions() | Request connection |
disconnect() | Disconnect wallet |
getAccounts() | Get connected accounts (return address, publicKey) |
getActiveChain() | Get the current chain |
signAndExecuteTransactionBlock(input) | To sign and execute the transaction, you need to pass in account/chain |
signTransactionBlock(input) | Only Sign transactions need to be passed in account/chain |
signAndExecuteTransaction(input) | Sign and execute (new API, uses Transaction, requires account/chain) |
signTransaction(input) | Signature transaction (new API, uses Transaction, requires account/chain) |
signMessage(input) | Signed message (old version, requires account/chain) |
signPersonalMessage(input) | Signed personal message (requires account/chain) |
Types
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;
}
Chain List
| Network | Identifier |
|---|---|
| Testnet | sui:testnet |
| Devnet | sui:devnet |
Handle Errors
try {
await provider.requestPermissions();
} catch (error) {
if (error.code === 4001) {
console.log("The connection request was declined");
} else {
console.error("Connection issue:", error.message);
}
}
Common error codes
| Code | Description |
|---|---|
| 4001 | User rejected the request |
| 4100 | Authorization required |
| -32603 | Provider internal failure |
Using Sui Wallet Kit
React projects can use Sui Wallet Kit. UKey Wallet will appear in the list of optional wallets through 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 is automatically detected via Sui Wallet Standard.
Using Sui SDK
import { SuiClient } from "@mysten/sui.js/client";
const client = new SuiClient({ url: "https://fullnode.mainnet.sui.io" });
// Retrieve balance
const balance = await client.getBalance({
owner: accountAddress,
});
// Retrieve object
const objects = await client.getOwnedObjects({
owner: accountAddress,
});
// Retrieve transaction
const txn = await client.getTransactionBlock({
digest: txDigest,
options: { showEffects: true },
});