Stake SUI with SDK
This tutorial provides a complete, end-to-end guide for building a simple web application that allows users to stake their SUI tokens directly from a browser wallet. We will delegate to the blockeden.xyz validator by interacting with the Sui blockchain using the official TypeScript SDK.
Why This Approach?
This method is designed with security and simplicity in mind, offering several key advantages for both developers and users:
- Zero Key Exposure: The user's private keys never leave their wallet. The wallet handles all cryptographic signing locally within its secure environment. Your application only constructs and requests a signature for a transaction, adhering to the best practices for non-custodial interactions.
- Universal Wallet Compatibility: By leveraging the
Sui Wallet Standard
, this approach works seamlessly with all major Sui wallets, including Sui Wallet, Suiet, Nightly, SafePal, and others. This frees you from writing wallet-specific code. - Reliable and Simple: The blockeden.xyz validator address is hard-coded into our application. This simplifies the logic and removes a potential point of failure or manipulation that could arise from fetching the address from an external, potentially compromised API.
Prerequisites
Before you start writing code, please ensure your development environment is set up with the following:
-
A funded Sui browser wallet: You'll need a browser extension wallet that supports the Sui Wallet Standard. Make sure it's funded with enough SUI to cover both the desired stake amount and the small network transaction fees (gas).
-
Node.js: You need Node.js version 18 or newer to run the TypeScript code and manage packages.
-
Sui Packages: Install the necessary Sui libraries using
npm
or your preferred package manager. Open your terminal and run:npm install @mysten/sui @mysten/wallet-standard
1. Set Up the Sui Client
The first step is to establish a connection to the Sui blockchain. We'll use the SuiClient
class from the @mysten/sui
library, which is our primary interface for reading data from the network.
import { SuiClient } from '@mysten/sui/client';
// Initialize a client for the Sui Mainnet
export const client = new SuiClient({
url: 'https://fullnode.mainnet.sui.io', // ← Switch to testnet/devnet if needed
});
This client instance will be used for tasks like fetching coin balances and querying stake information. Note that the RPC endpoint URL can be easily changed to point to 'https://fullnode.testnet.sui.io'
or 'https://fullnode.devnet.sui.io'
for testing.
2. Discover and Connect to the User's Wallet
Next, your application needs to find and connect to the user's installed browser wallet. The @mysten/wallet-standard
library provides a standardized way to handle this discovery and connection process.
import {
getWallets,
SUI_MAINNET_CHAIN,
StandardConnectFeature,
SuiSignAndExecuteTransactionFeature,
WalletWithRequiredFeatures,
} from '@mysten/wallet-standard';
// Define a type for a wallet that has the features we need
type SuiWallet = WalletWithRequiredFeatures<
StandardConnectFeature & SuiSignAndExecuteTransactionFeature
>;
export async function connectWallet(): Promise<{
wallet: SuiWallet;
address: string;
}> {
// getWallets() scans the browser for all compatible wallets
const wallets = getWallets() as unknown as SuiWallet[];
if (!wallets.length) {
throw new Error('No Sui-compatible wallet found in the browser');
}
// In a real dApp, you would present a UI for the user to select a wallet.
// For simplicity, we'll just pick the first one found.
const wallet = wallets[0];
// Trigger the wallet's connection prompt
await wallet.features['standard:connect'].connect({
chains: [SUI_MAINNET_CHAIN], // Specify we are connecting to Mainnet
});
// Ensure the user has authorized at least one account
const account = wallet.accounts[0];
if (!account) {
throw new Error('Wallet connected but no account authorised');
}
return { wallet, address: account.address };
}
This connectWallet
function finds available wallets, prompts the user to connect, and returns the connected wallet instance and the user's public address.
3. Define the BlockEden Validator Address
To delegate a stake, you must specify the unique address of the validator you wish to support. In this tutorial, we will hard-code the address for the blockeden.xyz validator to ensure we are staking to the correct entity.
// BlockEden.xyz mainnet validator Sui address (confirmed 2025-07-30)
export const BLOCKEDEN_VALIDATOR =
'0x3b5664bb0f8bb4a8be77f108180a9603e154711ab866de83c8344ae1f3ed4695';
4. Build the Staking Transaction
Now we'll construct the transaction payload. This step prepares the transaction but does not sign or send it. We use the powerful Transaction
class to define the series of actions to be executed on-chain.
import { Transaction } from '@mysten/sui/transactions';
import { SUI_SYSTEM_STATE_OBJECT_ID } from '@mysten/sui/utils';
export async function buildStakeTx(
owner: string,
stakeAmountSUI: number,
): Promise<Transaction> {
// Convert SUI to MIST (1 SUI = 1,000,000,000 MIST) using BigInt for precision
const amountMIST = BigInt(stakeAmountSUI) * BigInt(1_000_000_000);
// In Sui, you must specify which Coin object to use for payment.
// We'll fetch the user's coins and find one large enough for the stake.
const { data: coins } = await client.getCoins({
owner,
coinType: '0x2::sui::SUI',
});
const coin = coins.find((c) => BigInt(c.balance) >= amountMIST);
if (!coin) {
throw new Error(
`No single coin ≥ ${stakeAmountSUI} SUI; consolidate your funds first.`,
);
}
const tx = new Transaction();
tx.setSender(owner);
tx.setGasBudget(20_000_000); // Set a reasonable gas budget
// Create a new coin object with the exact amount to be staked.
// The 'splitCoins' command takes our large coin and splits it.
const [stakeCoin] = tx.splitCoins(tx.object(coin.coinObjectId), [
tx.pure.u64(amountMIST.toString()),
]);
// This is the core staking command. It calls the 'request_add_stake'
// function on the deep-rooted Sui System smart contract (0x3).
tx.moveCall({
target: '0x3::sui_system::request_add_stake',
arguments: [
tx.object(SUI_SYSTEM_STATE_OBJECT_ID), // The Sui system state object
stakeCoin, // The coin we are staking
tx.pure.address(BLOCKEDEN_VALIDATOR), // The validator's address
],
});
return tx;
}
This function performs a critical sequence: it finds a suitable Coin
object, splits off the exact amount needed for the stake, and then creates a moveCall
to the official request_add_stake
function.
5. Sign and Execute with the Wallet
With the transaction constructed, the final step is to pass it to the user's wallet for review, signing, and submission to the network.
export async function stakeSui(amount: number) {
const { wallet, address } = await connectWallet();
const tx = await buildStakeTx(address, amount);
// This feature passes the unsigned transaction to the wallet extension.
// The wallet prompts the user to approve, then signs and submits it.
const result = await wallet.features[
'sui:signAndExecuteTransaction'
].signAndExecuteTransaction({
transaction: tx,
account: wallet.accounts[0],
chain: SUI_MAINNET_CHAIN,
options: { showEffects: true, showObjectChanges: true }, // Request detailed results
});
console.log('Stake transaction submitted. Digest:', result.digest);
return result;
}
Calling this stakeSui
function orchestrates the entire flow. It connects to the wallet, builds the transaction, and hands it off to the wallet to complete the process securely. The returned digest
is the transaction's unique ID on the blockchain.
6. Verify Your Delegation
After your transaction is submitted, you can programmatically check on its status. Keep in mind that new delegations only become active at the start of the next epoch (~24 hours).
export async function listStakes(owner: string) {
const stakes = await client.getStakes({ owner });
if (!stakes.length) {
console.log('No active stakes found. New stakes activate at the next epoch.');
return;
}
// Format the stake data into a clean table for display
console.table(
stakes.flatMap((p) =>
p.stakes.map((s) => ({
validator: p.validatorAddress,
stakeId: s.stakedSuiId,
principalMIST: s.principal,
status: s.status,
})),
),
);
}
This function fetches all StakedSui
objects owned by the user and prints their details, allowing you to confirm your stake is active or pending.
7. Unstake Later
When you decide to withdraw your SUI, the process is similar. You'll need the stakedSuiId
from the previous step to identify which delegation to unstake.
export async function unstake(
stakeObjectId: string, // Get this ID from the listStakes() function
) {
const { wallet, address } = await connectWallet();
const tx = new Transaction();
tx.setSender(address);
// Build the transaction to call the 'request_withdraw_stake' function
tx.moveCall({
target: '0x3::sui_system::request_withdraw_stake',
arguments: [
tx.object(SUI_SYSTEM_STATE_OBJECT_ID),
tx.object(stakeObjectId),
],
});
// Send to the wallet for signing and execution
const res = await wallet.features[
'sui:signAndExecuteTransaction'
].signAndExecuteTransaction({
transaction: tx,
account: wallet.accounts[0],
chain: SUI_MAINNET_CHAIN,
});
console.log('Unstake request submitted. Digest:', res.digest);
return res;
}
Just like staking, unstaking requests are processed at the start of the next epoch.
Key Facts to Remember
- Epoch Cadence: Sui operates in epochs, which are roughly 24-hour periods. Any new stake delegations or withdrawal requests are queued and only take effect at the beginning of the next epoch.
- Gas Buffer: All transactions on the Sui network require a fee, known as gas. Always ensure your wallet holds a small amount of extra SUI beyond your intended stake amount to cover these transaction costs.
- Auto-Compounding Rewards: A key benefit of staking on Sui is that your rewards are automatically added to your staked principal at the end of every epoch. This means your rewards start earning their own rewards without any further action from you.
- Security First: Throughout this entire flow, your private key never leaves your wallet. The application only prepares the transaction details and asks your wallet for a signature, which is the gold standard for dApp security.
Additional Resources
- Sui Wallet Standard Specification
- Sui TypeScript SDK Documentation
- blockeden.xyz Validator Details
- Suiscan Explorer for a live view of validators and stake
Happy staking!