Docs

suix_queryEvents - Query Events with Fil...

Query and filter Sui blockchain events using suix_queryEvents RPC method. Search events by package, module, sender, transaction with pagination support using Dwellir's high-performance Sui infrastructure.

Queries and filters events emitted by transactions on the Sui blockchain with support for various search criteria and pagination.

Overview

The suix_queryEvents method is essential for monitoring smart contract activity, tracking specific events, and building event-driven applications on Sui. Events are emitted by Move modules during transaction execution and provide structured data about what happened during contract interactions. This method enables filtering by event type, sender, package, time range, and more.

Code Examples

Common Use Cases

1. DeFi Protocol Monitoring

JavaScript
async function monitorDEXActivity(dexPackageId) {
  const monitor = new EventMonitor(client);
  
  // Monitor swap events
  monitor.onEvent(`${dexPackageId}::dex::SwapExecuted`, async (event) => {
    const swap = event.parsedJson;
    console.log(`🔄 Swap: ${swap.amountIn} ${swap.tokenIn} -> ${swap.amountOut} ${swap.tokenOut}`);
    
    // Check for large trades
    if (parseInt(swap.amountIn) > 1000000000) { // Large SUI trades
      console.log('🚨 Large trade detected!');
      // Send alert to monitoring system
    }
  });
  
  // Monitor liquidity events
  monitor.onEvent(`${dexPackageId}::pool::LiquidityAdded`, async (event) => {
    console.log('💧 Liquidity added:', event.parsedJson);
  });
  
  await monitor.startMonitoring({ Package: dexPackageId });
}

2. NFT Marketplace Tracking

JavaScript
async function trackNFTSales(marketplacePackage) {
  const analytics = new EventAnalytics(client);
  
  const salesEvents = await analytics.client.getEventsByType(
    `${marketplacePackage}::marketplace::ItemSold`
  );
  
  const salesAnalysis = {
    totalSales: salesEvents.length,
    totalVolume: 0,
    averagePrice: 0,
    topCollections: {},
    priceDistribution: { under1: 0, under10: 0, under100: 0, over100: 0 }
  };
  
  salesEvents.forEach(event => {
    const sale = event.parsedJson;
    const price = parseInt(sale.price) / 1000000000; // Convert MIST to SUI
    
    salesAnalysis.totalVolume += price;
    
    // Track collections
    const collection = sale.collection || 'Unknown';
    salesAnalysis.topCollections[collection] = 
      (salesAnalysis.topCollections[collection] || 0) + 1;
    
    // Price distribution
    if (price < 1) salesAnalysis.priceDistribution.under1++;
    else if (price < 10) salesAnalysis.priceDistribution.under10++;
    else if (price < 100) salesAnalysis.priceDistribution.under100++;
    else salesAnalysis.priceDistribution.over100++;
  });
  
  salesAnalysis.averagePrice = salesAnalysis.totalVolume / salesAnalysis.totalSales;
  
  return salesAnalysis;
}

3. User Activity Analysis

JavaScript
async function analyzeUserActivity(userAddress) {
  const userEvents = await getAllEventsPaginated(
    { Sender: userAddress }, 
    20
  );
  
  const activity = {
    totalTransactions: userEvents.length,
    uniqueContracts: new Set(),
    activityByHour: {},
    mostUsedContracts: {},
    eventTypes: {}
  };
  
  userEvents.forEach(event => {
    // Track contracts used
    activity.uniqueContracts.add(event.packageId);
    
    // Track contract usage frequency
    const contract = event.packageId;
    activity.mostUsedContracts[contract] = 
      (activity.mostUsedContracts[contract] || 0) + 1;
    
    // Track event types
    activity.eventTypes[event.type] = 
      (activity.eventTypes[event.type] || 0) + 1;
    
    // Activity by hour
    const timestamp = parseInt(event.timestampMs || '0');
    if (timestamp > 0) {
      const hour = new Date(timestamp).getHours();
      activity.activityByHour[hour] = 
        (activity.activityByHour[hour] || 0) + 1;
    }
  });
  
  activity.uniqueContracts = activity.uniqueContracts.size;
  
  return activity;
}

4. Smart Contract Audit Trail

JavaScript
async function auditSmartContract(packageId, moduleNames) {
  const auditTrail = {
    package: packageId,
    modules: {},
    securityEvents: [],
    adminActions: [],
    upgradeEvents: [],
    totalInteractions: 0
  };
  
  for (const moduleName of moduleNames) {
    const moduleEvents = await getAllEventsPaginated({
      MoveModule: { package: packageId, module: moduleName }
    }, 50);
    
    auditTrail.modules[moduleName] = {
      totalEvents: moduleEvents.length,
      uniqueSenders: new Set(moduleEvents.map(e => e.sender)).size,
      eventTypes: {},
      recentActivity: []
    };
    
    moduleEvents.forEach(event => {
      auditTrail.totalInteractions++;
      
      // Categorize events
      const eventType = event.type.split('::').pop();
      auditTrail.modules[moduleName].eventTypes[eventType] = 
        (auditTrail.modules[moduleName].eventTypes[eventType] || 0) + 1;
      
      // Check for security-relevant events
      if (eventType.toLowerCase().includes('admin') || 
          eventType.toLowerCase().includes('owner') ||
          eventType.toLowerCase().includes('upgrade')) {
        
        if (eventType.toLowerCase().includes('upgrade')) {
          auditTrail.upgradeEvents.push({
            timestamp: event.timestampMs,
            event: eventType,
            sender: event.sender,
            data: event.parsedJson
          });
        } else {
          auditTrail.adminActions.push({
            timestamp: event.timestampMs,
            event: eventType,
            sender: event.sender,
            data: event.parsedJson
          });
        }
      }
      
      // Recent activity (last 24 hours)
      const dayAgo = Date.now() - (24 * 60 * 60 * 1000);
      if (parseInt(event.timestampMs || '0') > dayAgo) {
        auditTrail.modules[moduleName].recentActivity.push({
          timestamp: event.timestampMs,
          type: eventType,
          sender: event.sender
        });
      }
    });
  }
  
  return auditTrail;
}

Best Practices

1. Efficient Event Filtering

JavaScript
// Use specific filters to reduce data transfer and improve performance
const specificFilter = {
  And: [
    { Package: '0x2' },
    { MoveEventType: '0x2::coin::CoinCreated' }
  ]
};

// Avoid overly broad queries
const tooBoard = { All: [] }; // Can return massive amounts of data

2. Event Data Parsing

JavaScript
function safeParseEventData(event) {
  try {
    return {
      type: event.type,
      data: event.parsedJson,
      timestamp: parseInt(event.timestampMs || '0'),
      sender: event.sender,
      package: event.packageId,
      module: event.transactionModule
    };
  } catch (error) {
    console.warn('Failed to parse event:', error);
    return {
      type: event.type || 'Unknown',
      data: null,
      error: error.message
    };
  }
}

3. Performance Optimization

JavaScript
// Use pagination for large datasets
async function efficientEventQuery(filter, maxEvents = 10000) {
  const events = [];
  let cursor = null;
  let retrieved = 0;
  
  while (retrieved < maxEvents) {
    const batchSize = Math.min(100, maxEvents - retrieved);
    
    const result = await client.queryEvents({
      query: filter,
      cursor: cursor,
      limit: batchSize,
      order: 'descending'
    });
    
    if (!result.data.length) break;
    
    events.push(...result.data);
    retrieved += result.data.length;
    
    if (!result.hasNextPage) break;
    cursor = result.nextCursor;
    
    // Small delay to prevent overwhelming the RPC
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return events;
}

Notes

  • Events are immutable once emitted by transactions
  • Pagination is essential for large result sets to avoid timeouts
  • Event data structure depends on the Move module that emitted it
  • Timestamps are in milliseconds since Unix epoch
  • BCS encoding provides raw event data for custom parsing
  • Filter combinations using And/Or can create complex queries

Need help? Contact our support team or check the Sui documentation.