---
title: "Stake SUI with SDK"
tags: [SUI, SDK, blockchain, staking, web application]
keywords: [SUI staking, blockchain SDK, web app development, browser wallet, TypeScript]
description: "Learn how to build a secure web application for staking SUI tokens using the official TypeScript SDK, ensuring zero key exposure and universal wallet compatibility."
authors: [dora]
image: "https://bex.co/api/og-bex-co?title=Stake%20SUI%20with%20SDK"
last_updated: 2026-08-19
---


# 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 **bex.co** 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 **bex.co** 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:

  ```bash
  npm install @mysten/sui @mysten/dapp-kit
  ```

-----

## 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.

```typescript
import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';

// Initialize a client for the Sui Mainnet
export const client = new SuiClient({
  url: getFullnodeUrl('mainnet'), // ← Switch to 'testnet' or 'devnet' if needed
});
```

This client instance will be used for tasks like fetching coin balances and querying stake information. Note that you can easily switch networks by changing the parameter to `getFullnodeUrl('testnet')` or `getFullnodeUrl('devnet')` 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.

```typescript
import {
  getWallets,
  SUI_MAINNET_CHAIN,
  StandardConnectFeature,
  SuiSignAndExecuteTransactionFeature,
  WalletWithRequiredFeatures,
} from '@mysten/dapp-kit';

// 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 bex.co 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 **bex.co** validator to ensure we are staking to the correct entity.

```typescript
// bex.co mainnet validator Sui address (confirmed 2025-07-30)
export const BEX_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.

```typescript
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) * 1_000_000_000n;

  // 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), [
    amountMIST,
  ]);

  // 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(BEX_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.

```typescript
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).

```typescript
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.

```typescript
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](https://www.google.com/search?q=https://github.com/MystenLabs/sui/tree/main/sdk/wallet-standard)
* [Sui TypeScript SDK Documentation](https://sdk.mystenlabs.com/typescript)
* [bex.co Validator Details](https://bex.co/)
* [Suiscan Explorer](https://suiscan.xyz/mainnet/validators) for a live view of validators and stake

Happy staking\!
