Skip to main content

πŸ”§ Dubhe Engine Client SDK

Type-safe TypeScript SDK for seamless blockchain interaction

v2.0.0TypeScriptReal-time
Package: @0xobelisk/dubhe-client
License: Apache-2.0
GitHub: View Source

πŸ“¦ Installation

npm install @0xobelisk/dubhe-client

⚑ Quick Start

import { DubheClient } from '@0xobelisk/dubhe-client';

const client = new DubheClient({
  network: 'devnet',
  packageId: 'YOUR_PACKAGE_ID'
});

// Query component data
const player = await client.getComponent({
  entity: 'PLAYER_ENTITY_ID',
  component: 'PlayerComponent'
});

// Execute system function
const txb = await client.tx.player_system.move({
  player: 'PLAYER_ID',
  direction: { x: 10, y: 5 }
});

const result = await client.signAndExecute(txb);

πŸ—οΈ DubheClient Class

Constructor

new DubheClient(config: DubheClientConfig)

DubheClientConfig

PropertyTypeRequiredDescription
network'mainnet' | 'testnet' | 'devnet' | 'localnet'βœ…Sui network to connect to
packageIdstringβœ…Your deployed package ID
endpointstring❌Custom RPC endpoint
optionsClientOptions❌Additional configuration

ClientOptions

PropertyTypeDefaultDescription
enableCachebooleanfalseEnable query result caching
cacheTimeoutnumber30000Cache timeout in milliseconds
retryAttemptsnumber3Number of retry attempts for failed requests
subscriptionTimeoutnumber60000WebSocket subscription timeout
gasPricenumber1000Default gas price for transactions

πŸ“Š Component Operations

Components are the data containers in Dubhe’s ECS architecture. Use these methods to read and query on-chain state.

getComponent()

Retrieve a single component for an entity.
getComponent<T>(params: GetComponentParams): Promise<T | null>

Parameters

interface GetComponentParams {
  entity: string      // Entity ID
  component: string   // Component name (must match Move struct name)
}

Example

const playerData = await client.getComponent({
  entity: '0x123...',
  component: 'PlayerComponent'
});

if (playerData) {
  console.log(`Player health: ${playerData.health}`);
  console.log(`Player level: ${playerData.level}`);
}

queryComponents()

Query multiple components with filtering.
queryComponents<T>(params: QueryComponentsParams): Promise<T[]>

Parameters

interface QueryComponentsParams {
  component: string           // Component name
  filter?: ComponentFilter    // Optional filtering criteria
  limit?: number             // Maximum number of results
  offset?: number            // Pagination offset
}

interface ComponentFilter {
  [field: string]: any       // Field-specific filters
  entityId?: {
    $in?: string[]          // Match any of these entity IDs
    $nin?: string[]         // Exclude these entity IDs
  }
}

Example

// Get all players with health > 50
const alivePlayers = await client.queryComponents({
  component: 'PlayerComponent',
  filter: {
    health: { $gt: 50 }
  },
  limit: 100
});

// Get specific players
const specificPlayers = await client.queryComponents({
  component: 'PlayerComponent',
  filter: {
    entityId: { $in: ['0x123...', '0x456...'] }
  }
});

πŸ’« Transaction Operations

Always ensure you have sufficient SUI for gas fees before executing transactions.

System Transactions

Access generated system transaction builders through the tx property:
client.tx.system_name.function_name(params)

Example

// Player movement system
const moveTxb = await client.tx.player_system.move({
  player: 'PLAYER_ID',
  direction: { x: 10, y: 5 }
});

// Battle system
const attackTxb = await client.tx.battle_system.attack({
  attacker: 'ATTACKER_ID',
  target: 'TARGET_ID',
  weapon: 'WEAPON_ID'
});

// Inventory system
const equipTxb = await client.tx.inventory_system.equip_item({
  player: 'PLAYER_ID',
  item: 'ITEM_ID',
  slot: 'weapon'
});

signAndExecute()

Sign and execute a transaction block.
signAndExecute(txb: TransactionBlock): Promise<TransactionResult>

TransactionResult

interface TransactionResult {
  digest: string                    // Transaction hash
  effects: TransactionEffects       // Transaction effects
  events: Event[]                   // Emitted events
  gasUsed: number                   // Gas consumed
  success: boolean                  // Transaction success status
}

Example

try {
  const result = await client.signAndExecute(moveTxb);
  
  if (result.success) {
    console.log('Transaction successful:', result.digest);
    console.log('Gas used:', result.gasUsed);
  }
} catch (error) {
  console.error('Transaction failed:', error.message);
}

πŸ”„ Real-time Subscriptions

Subscriptions use WebSocket connections for real-time updates. Remember to clean up subscriptions when components unmount.

subscribe()

Subscribe to real-time component updates.
subscribe<T>(
  params: SubscribeParams, 
  callback: (data: T) => void
): () => void

Parameters

interface SubscribeParams {
  entity?: string       // Specific entity ID
  component: string     // Component name
  filter?: ComponentFilter  // Optional filtering
}

Example

// Subscribe to a specific player
const unsubscribe = client.subscribe({
  entity: 'PLAYER_ID',
  component: 'PlayerComponent'
}, (updatedPlayer) => {
  console.log('Player updated:', updatedPlayer);
  updateUI(updatedPlayer);
});

// Subscribe to all players
const unsubscribeAll = client.subscribe({
  component: 'PlayerComponent'
}, (players) => {
  console.log('Players updated:', players.length);
  updatePlayerList(players);
});

// Clean up subscriptions
unsubscribe();
unsubscribeAll();

subscribeToComponent()

Subscribe to all entities of a specific component type.
subscribeToComponent<T>(
  componentName: string,
  callback: (entities: ComponentData<T>[]) => void
): () => void

Example

const unsubscribe = client.subscribeToComponent(
  'PlayerComponent',
  (entities) => {
    entities.forEach(entity => {
      console.log(`Entity ${entity.id} updated:`, entity.data);
    });
  }
);

⚠️ Error Handling

Common Errors

Error CodeDescriptionSolution
COMPONENT_NOT_FOUNDComponent doesn’t exist for entityCheck entity ID and component name
INSUFFICIENT_GASNot enough SUI for transaction feesAdd SUI to wallet
INVALID_SIGNATURETransaction signature invalidCheck wallet connection
NETWORK_ERRORCannot connect to Sui networkCheck network configuration
PACKAGE_NOT_FOUNDPackage ID not foundVerify package deployment

Error Handling Example

try {
  const component = await client.getComponent({
    entity: entityId,
    component: 'PlayerComponent'
  });
} catch (error) {
  switch (error.code) {
    case 'COMPONENT_NOT_FOUND':
      console.log('Player component not found');
      break;
    case 'NETWORK_ERROR':
      console.log('Network connection failed');
      break;
    default:
      console.error('Unexpected error:', error);
  }
}

πŸš€ Performance Tips

  1. Enable caching for frequently accessed data
  2. Batch operations to reduce network calls
  3. Use selective subscriptions to minimize data transfer
  4. Implement pagination for large datasets
  5. Handle errors gracefully with retry logic

Caching

Enable caching for frequently accessed data:
const client = new DubheClient({
  network: 'devnet',
  packageId: '0x...',
  options: {
    enableCache: true,
    cacheTimeout: 30000  // 30 seconds
  }
});

Batch Operations

Batch multiple queries for better performance:
// Instead of multiple getComponent calls
const [player, inventory, stats] = await Promise.all([
  client.getComponent({ entity: id, component: 'PlayerComponent' }),
  client.getComponent({ entity: id, component: 'InventoryComponent' }),
  client.getComponent({ entity: id, component: 'StatsComponent' })
]);

Selective Subscriptions

Only subscribe to components you actively display:
// Good: Subscribe only to visible players
const unsubscribe = client.subscribe({
  component: 'PlayerComponent',
  filter: { zone: currentZone }
}, updateVisiblePlayers);

// Avoid: Subscribing to all entities

🎯 Next Steps

Smart Contracts

Explore Move contract interfaces

Schema Definitions

Understand data structures

Tutorial

Build your first DApp