Sui.

Post

Share your knowledge.

Evgeniy CRYPTOCOIN.
Jun 26, 2025
Expert Q&A

How to Properly Use the Sui SDK for Frontend Integration?

I'm building a frontend (React/Next.js) for a Sui dApp and need to interact with the blockchain—fetching objects, sending transactions, and listening to events. I’ve tried using the @mysten/sui.js SDK, but I’m running into issues:

Wallet Connection: Sometimes, the wallet doesn’t return the user’s address after connecting.

Transaction Handling: Transactions fail silently or return vague errors.

RPC Limits: I get rate-limited or timeouts when fetching large datasets.

Real-Time Updates: How can I listen for on-chain events (e.g., NFT mints, balance changes)?

What I’ve tried:

✔ Basic SuiClient setup with mainnet and testnet RPCs.

✔ Using useWallet() from @mysten/dapp-kit for wallet integration.

✔ Manual transaction signing with signAndExecuteTransactionBlock.

Questions:

What’s the recommended way to initialize the Sui SDK in a frontend app?

How do I handle errors gracefully (e.g., RPC failures, wallet rejections)?

Are there best practices for optimizing queries (batching, caching, etc.)?

How can I subscribe to real-time updates (e.g., new transactions, object changes)?

  • Sui
  • SDKs and Developer Tools
6
2
Share
Comments
.

Answers

2
Benjamin XDV.
Jun 30 2025, 18:13

Expert Answer:

  1. Initializing the Sui SDK The @mysten/sui.js SDK should be configured with a reliable RPC endpoint. For production apps, consider:

Default RPCs:

ts
import { SuiClient, getFullnodeUrl } from '@mysten/sui.js/client';  

const client = new SuiClient({ url: getFullnodeUrl('mainnet') });  

Fallback RPCs: Use services like Sui RPC Providers to avoid rate limits.

For wallet integration, use @mysten/dapp-kit:

tsx
import { createNetworkConfig, SuiClientProvider, WalletProvider } from '@mysten/dapp-kit';  
import { getFullnodeUrl } from '@mysten/sui.js/client';  

const { networkConfig } = createNetworkConfig({  
  mainnet: { url: getFullnodeUrl('mainnet') },  
  testnet: { url: getFullnodeUrl('testnet') },  
});  

function App() {  
  return (  
    <SuiClientProvider networks={networkConfig} defaultNetwork="mainnet">  
      <WalletProvider autoConnect>  
        <YourApp />  
      </WalletProvider>  
    </SuiClientProvider>  
  );  
}  
  1. Handling Transactions & Errors Always wrap transactions in error handling:

ts

try {  
  const tx = await signAndExecuteTransactionBlock({  
    transactionBlock: txBlock,  
    options: { showEffects: true },  
  });  
  console.log("Tx Digest:", tx.digest);  
} catch (err) {  
  console.error("Tx Failed:", err.message);  
  // Handle specific errors (e.g., user rejection, insufficient gas)  
}  

Common errors:

"User rejected the request" → Wallet popup was closed.

"Gas budget exceeded" → Increase gas budget with txBlock.setGasBudget().

"Object not found" → Check if the object ID is correct and still exists.

  1. Optimizing RPC Calls Batching Requests: Use multiGetObjects for fetching multiple objects in one call.

Caching: Use React Query or SWR to cache RPC responses:

ts
import { useSuiClientQuery } from '@mysten/dapp-kit';  

const { data } = useSuiClientQuery('getObject', {  
  id: objectId,  
  options: { showContent: true },  
});  

Pagination: For large datasets, use suix_getDynamicFields with cursors.

  1. Real-Time Updates Use WebSockets or polling:

WebSocket Subscriptions (advanced):

ts
const unsubscribe = client.subscribeEvent({  
  filter: { sender: '0x123...' },  
  onMessage(event) { console.log("New event:", event); },  
});  

// Cleanup on unmount
return () => unsubscribe();
Polling with Hooks:

ts
useSuiClientSubscription('subscribeEvent', {  
  filter: { eventType: 'ExampleEvent' },  
  onData(event) { console.log("Event:", event); },  
});  

Pro Tips

  1. Use @mysten/dapp-kit for pre-built wallet hooks.
  2. Set a custom gas budget for complex transactions.
  3. Monitor RPC health – switch endpoints if responses are slow.
  4. Test on Testnet before mainnet deployment.
2
Best Answer
Comments
.
HaGiang.
Jun 30 2025, 05:57

1. Recommended SDK Initialization

For a production-grade React or Next.js dApp, the recommended stack combines three key packages. This setup separates low-level blockchain interaction from application state management.[1, 2, 3]

  • Core Libraries:

    • @mysten/sui.js: The foundational TypeScript SDK for all direct Sui network interactions.[4]
    • @mysten/dapp-kit: The primary React library with hooks and components for wallet connection and data fetching.[2, 5, 6]
    • @tanstack/react-query: A required dependency for @mysten/dapp-kit that handles caching, re-fetching, and managing on-chain data as server state.[1, 7]
  • Provider Setup: Wrap your application's root component with these providers in the correct order to ensure all hooks function properly.[3, 4]

    import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
    import { SuiClientProvider, WalletProvider, createNetworkConfig } from '@mysten/dapp-kit';
    import { getFullnodeUrl } from '@mysten/sui/client';
    import '@mysten/dapp-kit/dist/index.css';
    
    const queryClient = new QueryClient();
    const { networkConfig } = createNetworkConfig({
      mainnet: { url: getFullnodeUrl('mainnet') },
      testnet: { url: getFullnodeUrl('testnet') },
    });
    
    function AppRoot() {
      return (
        <QueryClientProvider client={queryClient}>
          <SuiClientProvider networks={networkConfig} defaultNetwork="mainnet">
            <WalletProvider autoConnect>
              {/* Your Application Components */}
            </WalletProvider>
          </SuiClientProvider>
        </QueryClientProvider>
      );
    }
    

2. Graceful Error Handling

Handling errors effectively is crucial for user experience. Here’s how to manage common issues.

  • Wallet Connection Failures: The issue of a wallet address not being available immediately after connection is typically an asynchronous state problem.

    • Solution: Always check if the account object returned by the useCurrentAccount() hook is null. When fetching data that depends on the address, use the enabled:!!account option in useSuiClientQuery to prevent the query from running until the address is available.[3]
  • Transaction Errors: Raw RPC errors are often cryptic. Use the suiclient-error-decoder library to translate them into human-readable messages.[8, 9]

    • Strategy: Coordinate with your smart contract developer to define a map of error codes. In your frontend, use this map with the decoder to parse errors caught in a try...catch block .
    import { useSignAndExecuteTransactionBlock } from '@mysten/dapp-kit';
    import { SuiClientErrorDecoder } from 'suiclient-error-decoder';
    
    // 1. Define your custom error map
    const myErrorMap = { 1: "Mint limit has been reached." };
    const errorDecoder = new SuiClientErrorDecoder({ customErrorCodes: myErrorMap });
    
    // 2. Wrap your transaction call
    const { mutateAsync: signAndExecute } = useSignAndExecuteTransactionBlock();
    
    async function handleMint(txb) {
      try {
        await signAndExecute({ transactionBlock: txb });
        console.log("Transaction successful!");
      } catch (error) {
        const decodedError = errorDecoder.parseError(error);
        // Display decodedError.message to the user
        console.error(decodedError.message); 
      }
    }
    
    • Common Errors:
      • "User rejected the request": The user closed the wallet pop-up.[10, 11]
      • "InsufficientGas": The gas budget was too low. Let the wallet auto-set the budget; avoid setting it manually unless necessary .

3. Optimizing Queries

To avoid RPC rate limits and improve performance, use a combination of batching, pagination, and caching.

  • Batching: Instead of fetching objects one by one, use sui_multiGetObjects to retrieve data for up to 50 object IDs in a single request. This significantly reduces network traffic .

  • Pagination: For large datasets like an object's dynamic fields, use paginated endpoints like suix_getDynamicFields. These endpoints use a cursor to fetch data page by page, preventing timeouts .

  • Caching: The useSuiClientQuery hook from @mysten/dapp-kit automatically caches responses.[1, 5] To further optimize, set a staleTime for data that doesn't change frequently (e.g., NFT metadata). This tells React Query to serve cached data for a specified duration before re-fetching, reducing redundant RPC calls.[7, 12, 13]

    const { data } = useSuiClientQuery(
      'getObject',
      { id: objectId, options: { showContent: true } },
      { staleTime: 10 * 60 * 1000 } // Cache is fresh for 10 minutes
    );
    
  • RPC Providers: For production applications, use a dedicated RPC provider like QuickNode, Ankr, or Chainstack to ensure reliability and avoid the strict rate limits of public endpoints.[14, 15, 16]

4. Real-Time Updates

There are three primary methods for listening to on-chain events, each with different trade-offs.

  1. Polling: The simplest method. Use useSuiClientQuery with a refetchInterval to periodically ask the network for updates. This is suitable for non-critical data where a delay of a few seconds is acceptable.[17]

  2. WebSocket Subscriptions: This method offers low-latency, real-time updates. However, the official Sui JSON-RPC WebSocket API is deprecated, so you must use a third-party RPC provider that offers WebSocket support.[18, 19] You can use client.subscribeEvent to listen for specific events and must manage the subscription lifecycle carefully within a React useEffect hook to prevent memory leaks.[20, 21, 22]

    useEffect(() => {
      const unsubscribe = await client.subscribeEvent({
        filter: { MoveEventModule: { package: '0x...', module: 'my_module' } },
        onMessage: (event) => {
          console.log("New event:", event);
        },
      });
    
      // Cleanup on component unmount
      return () => {
        unsubscribe();
      };
    },);
    
  3. Custom Indexer: The most powerful and reliable solution for mission-critical applications. An indexer is a dedicated backend service that processes all on-chain data and stores it in an optimized database. This allows for complex, low-latency queries that are not possible with the standard RPC API. This approach is recommended for production-grade DeFi, gaming, or analytics platforms.[9, 23, 24]

2
Comments
.

Do you know the answer?

Please log in and share it.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

367Posts503Answers
Sui.X.Peera.

Earn Your Share of 1000 Sui

Gain Reputation Points & Get Rewards for Helping the Sui Community Grow.

Reward CampaignJuly