| title | Client - Dubhe |
|---|---|
| description | Learn how to use the Sui Client. |
Before getting started with Dubhe Client SDK, please install the required dependencies:
pnpm install @0xobelisk/sui-client @0xobelisk/sui-commonNote: @0xobelisk/sui-common contains essential configuration type definitions like DubheConfig, which are necessary for contract development.
Dubhe is a client-agnostic SDK that supports various platforms including browsers, Node.js, and the COCOS game engine. It provides a simple interface to interact with your Sui Move contracts.
Before using the SDK, make sure you have:
- Created and deployed your contract using the Dubhe CLI
- Obtained the
packageIdafter deployment
First, define your contract's configuration using DubheConfig:
import { DubheConfig } from "@0xobelisk/sui-common";
export const dubheConfig = {
name: "counter",
description: "counter",
systems: ["counter"],
schemas: {
counter: {
structure: {
value: "StorageValue<u32>",
},
},
},
} as DubheConfig;Generate the contract code using CLI:
pnpm dubhe schemagenThere are two ways to initialize the Dubhe client:
- Using dynamic metadata loading:
import { loadMetadata, Dubhe, NetworkType } from "@0xobelisk/sui-client";
const network = "testnet" as NetworkType;
const packageId = "YOUR_PACKAGE_ID";
const metadata = await loadMetadata(network, packageId);
const dubhe = new Dubhe({
networkType: network,
packageId: packageId,
metadata: metadata,
secretKey: privkey,
});- Using pre-saved metadata (recommended for better performance):
import metadata from "./metadata.json";
const dubhe = new Dubhe({
networkType: network,
packageId: packageId,
metadata: metadata,
secretKey: privkey,
});The Dubhe constructor accepts the following parameters:
interface DubheParams {
// Authentication (one of these is required)
mnemonics?: string; // 12 or 24 mnemonic words, separated by space
secretKey?: string; // Base64 or hex string or bech32 format private key
// Note: if mnemonics is provided, secretKey will be ignored
// Network Configuration
networkType?: NetworkType; // 'mainnet' | 'testnet' | 'devnet' | 'localnet'
// Default: 'mainnet'
fullnodeUrls?: string[]; // Array of fullnode URLs
// Default: Network-specific default URL
faucetUrl?: string; // Custom faucet URL for testnet/devnet/localnet
// Contract Configuration
packageId?: string; // Your contract's package ID
metadata?: SuiMoveNormalizedModules; // Contract metadata
// Indexer Configuration
indexerUrl?: string; // Custom indexer API URL
indexerWsUrl?: string; // Custom indexer WebSocket URL
// Default: Derived from indexerUrl
// HTTP Configuration
customFetch?: typeof fetch; // Custom fetch implementation
defaultOptions?: FetchOptions; // Default fetch options for all requests
}- Basic initialization with private key:
const dubhe = new Dubhe({
networkType: "testnet",
packageId: "0x123...",
metadata: metadata,
secretKey: "YOUR_PRIVATE_KEY",
});- Using mnemonics with custom network configuration:
const dubhe = new Dubhe({
mnemonics: "word1 word2 ... word24",
networkType: "testnet",
fullnodeUrls: ["https://custom-fullnode.example.com"],
packageId: "0x123...",
metadata: metadata,
});- With custom indexer configuration:
const dubhe = new Dubhe({
secretKey: "YOUR_PRIVATE_KEY",
networkType: "mainnet",
packageId: "0x123...",
metadata: metadata,
indexerUrl: "https://custom-indexer.example.com",
indexerWsUrl: "wss://custom-indexer-ws.example.com",
});To call contract methods:
import { Transaction } from "@0xobelisk/sui-client";
// Create transaction
const tx = new Transaction();
// Execute transaction with callbacks
const response = await dubhe.tx.counter_system.inc({
tx,
params: [
/* your parameters */
],
typeArguments: ["0x2::coin::Coin<0x2::sui::SUI>"], // optional
isRaw: false, // optional, defaults to false
onSuccess: async (result) => {
// Handle successful transaction
console.log("Transaction succeeded:", result.digest);
await dubhe.waitForTransaction(result.digest);
},
onError: (error) => {
// Handle transaction error
console.error("Transaction failed:", error);
},
});
// For wallet integration
const walletTx = await dubhe.tx.counter_system.inc({
tx,
params: [
/* your parameters */
],
typeArguments: [],
isRaw: true,
});
const response = await dubhe.signAndSendTxn({
tx: walletTx,
onSuccess: async (result) => {
// Handle successful transaction
console.log("Transaction succeeded:", result.digest);
await dubhe.waitForTransaction(result.digest);
},
onError: (error) => {
// Handle transaction error
console.error("Transaction failed:", error);
},
});Both query and transaction methods accept a parameter structure with the following fields:
{
tx: Transaction; // Required: Transaction instance
params?: TransactionArg[]; // Optional: Array of transaction arguments
typeArguments?: string[]; // Optional: Generic type arguments
isRaw?: boolean; // Optional: Return raw transaction instead of executing
onSuccess?: (result: SuiTransactionBlockResponse) => void | Promise<void>; // Optional: Success callback
onError?: (error: Error) => void | Promise<void>; // Optional: Error callback
}Here's a practical example showing how to use callbacks:
const tx = new Transaction();
try {
await dubhe.tx.map_system.register({
tx,
params: [
/* your parameters */
],
onSuccess: async (result) => {
// Add delay if needed
setTimeout(async () => {
// Show success notification
toast("Register Successful", {
description: new Date().toUTCString(),
action: {
label: "Check in Explorer",
onClick: () =>
window.open(dubhe.getTxExplorerUrl(result.digest), "_blank"),
},
});
}, 2000);
// Wait for transaction to be confirmed
await dubhe.waitForTransaction(result.digest);
},
onError: (error) => {
console.error("Transaction failed:", error);
toast.error("Transaction failed. Please try again.");
},
});
} catch (error) {
// Handle any unexpected errors
console.error("Unexpected error:", error);
}To query contract state:
// Create transaction
const tx = new Transaction();
// Query with struct parameters
const result = await dubhe.query.counter_system.get({
tx,
params: [
/* your parameters */
],
typeArguments: [], // optional
isRaw: false, // optional
});
// For BCS encoded results
const decodedData = dubhe.view(result);The SDK provides a view() method to decode BCS-encoded return values from contract queries.
For detailed examples and advanced usage of querying data, please refer to our Query With Client Guide.
- Basic types (u8, u16, u32, u64, u128, u256)
- Boolean
- String
- Vector
- Struct
- Option
- Custom objects
// Example contract return type
struct GameState {
score: u64,
player_name: String,
is_active: bool,
items: vector<Item>
}
// Query and decode
const tx = new Transaction();
const result = await dubhe.query.game_system.get_state(tx, params);
const decodedState = dubhe.view(result);Some complex nested structures might require additional handling.
To query the state of schema fields defined in your Dubhe config, you can use either parseState() or state() method:
const result = await dubhe.parseState({
schema: "counter", // Schema name from your Dubhe config
objectId: "0x123...", // Object ID of the schema instance
storageType: "StorageValue<u64>", // Storage type of the field
params: [], // Parameters for StorageMap/StorageDoubleMap keys
});const tx = new Transaction();
const result = await dubhe.state({
tx, // Transaction instance
schema: "counter", // Schema name from your Dubhe config
params: [tx.object("0x123...")], // Parameters including object ID
});The storage types support three formats:
StorageValue<V>- For single value storage
// Query a simple storage value
const value = await dubhe.parseState({
schema: "player",
objectId: "0x123...",
storageType: "StorageValue<u64>",
params: [], // No params needed for StorageValue
});StorageMap<K,V>- For key-value map storage
// Query a value from storage map
const mapValue = await dubhe.parseState({
schema: "inventory",
objectId: "0x123...",
storageType: "StorageMap<address,u64>",
params: ["0x456..."], // Key to look up in the map
});StorageDoubleMap<K1,K2,V>- For double key-value map storage
// Query a value from double map
const doubleMapValue = await dubhe.parseState({
schema: "game",
objectId: "0x123...",
storageType: "StorageDoubleMap<address,u64,u64>",
params: ["0x456...", 42], // Two keys needed for double map
});The following key types are supported for StorageMap and StorageDoubleMap:
- Basic types:
u8,u16,u32,u64,u128,u256,bool address- Custom object types (format:
package::module::type)
The method will throw an error if:
- Invalid storage type format is provided
- Wrong number of parameters for the storage type
- Unsupported key type is used
- Schema doesn't exist
- Object ID is invalid
- StorageValue: No additional parameters required
- StorageMap: Exactly one key parameter required
- StorageDoubleMap: Exactly two key parameters required
-
Use pre-saved metadata for better performance in production
- Generate and save metadata during deployment
- Load metadata from file instead of fetching it every time
-
Implement proper error handling for BCS decoding
- Handle potential decoding errors for complex types
- Validate data types before decoding
- Use try-catch blocks for parsing operations
-
Consider the limitations of enum type handling when designing your contract return types
- Be aware of Sui metadata limitations for enums
- Design simpler enum structures when possible
- Test enum handling thoroughly
For more information or support, please visit our GitHub repository or join our community channels.