Skip to main content

suix_queryEvents

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.

Parameters​

ParameterTypeRequiredDescription
queryobjectYesQuery criteria to filter events
cursorstringNoPagination cursor from previous response
limitnumberNoMaximum number of events to return (default: 50, max: 1000)
descendingOrderbooleanNoReturn results in descending order by sequence number (default: false)

Query Object​

The query object supports various filter types:

Filter TypeDescriptionExample
AllMatch all events (no filter){ "All": [] }
TransactionEvents from specific transaction{ "Transaction": "0x123..." }
MoveModuleEvents from specific Move module{ "MoveModule": { "package": "0x2", "module": "coin" } }
MoveEventTypeEvents of specific Move event type{ "MoveEventType": "0x2::coin::Deposit" }
SenderEvents from transactions by specific sender{ "Sender": "0x456..." }
PackageEvents from any module in package{ "Package": "0x789..." }
TimeRangeEvents within time range{ "TimeRange": { "startTime": 1234567890, "endTime": 1234567900 } }

Complex Query Filters​

Filter TypeDescriptionStructure
AndAll conditions must match{ "And": [filter1, filter2] }
OrAny condition must match{ "Or": [filter1, filter2] }

Returns​

Returns a paginated response containing matching events.

FieldTypeDescription
dataarrayArray of event objects matching the query
nextCursorstringCursor for next page (null if no more pages)
hasNextPagebooleanWhether more pages are available

Event Object Structure​

FieldTypeDescription
idobjectEvent identifier with transaction digest and event sequence
packageIdstringPackage that emitted the event
transactionModulestringModule name that emitted the event
senderstringAddress of transaction sender
typestringFull event type (package::module::EventName)
parsedJsonobjectEvent data parsed as JSON
bcsstringBCS-encoded event data
timestampMsstringEvent timestamp in milliseconds

Code Examples​

# Query all events (with limit)
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_queryEvents",
"params": [
{
"All": []
},
null,
10,
true
],
"id": 1
}'

# Query events from specific package
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_queryEvents",
"params": [
{
"Package": "0x2"
},
null,
50,
true
],
"id": 1
}'

# Query specific event type
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_queryEvents",
"params": [
{
"MoveEventType": "0x2::coin::CoinCreated"
},
null,
100,
true
],
"id": 1
}'

# Query events from specific sender
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_queryEvents",
"params": [
{
"Sender": "0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f"
},
null,
25,
true
],
"id": 1
}'

# Query events with complex filter (AND condition)
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_queryEvents",
"params": [
{
"And": [
{
"Package": "0x2"
},
{
"Sender": "0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f"
}
]
},
null,
30,
true
],
"id": 1
}'

Response Example​

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"data": [
{
"id": {
"txDigest": "0x8c123c0b23c456789abcdef0123456789abcdef0123456789abcdef0123456789a",
"eventSeq": "0"
},
"packageId": "0x2",
"transactionModule": "coin",
"sender": "0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f",
"type": "0x2::coin::CoinCreated",
"parsedJson": {
"coinType": "0x2::sui::SUI",
"creator": "0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f",
"initialSupply": "1000000000"
},
"bcs": "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiM=",
"timestampMs": "1703097600000"
},
{
"id": {
"txDigest": "0x7d456e78f90123456789abcdef0123456789abcdef0123456789abcdef012345",
"eventSeq": "1"
},
"packageId": "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55",
"transactionModule": "dex",
"sender": "0x1a2b3c4d5e6f789012345678901234567890123456789012345678901234567890",
"type": "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::dex::SwapExecuted",
"parsedJson": {
"trader": "0x1a2b3c4d5e6f789012345678901234567890123456789012345678901234567890",
"tokenIn": "0x2::sui::SUI",
"tokenOut": "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
"amountIn": "500000000",
"amountOut": "125000",
"feeAmount": "1500000"
},
"bcs": "HGERFOWPgergpowejrgpowejrgpowejrgpowerjgpowerjgpowejrgp",
"timestampMs": "1703097610000"
}
],
"nextCursor": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"hasNextPage": true
}
}

Common Use Cases​

1. DeFi Protocol Monitoring​

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​

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​

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​

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​

// 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​

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​

// 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;
}

Error Handling​

async function robustEventQuery(filter, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const result = await client.queryEvents({ query: filter });
return { success: true, data: result };
} catch (error) {
console.warn(`Query attempt ${i + 1} failed:`, error.message);

if (i === retries - 1) {
return {
success: false,
error: error.message,
retryExhausted: true
};
}

// Exponential backoff
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, i) * 1000)
);
}
}
}

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.