Skip to main content

Overview

The ZKScore Score Calculator contract emits events for all significant score changes and configuration updates. These events are essential for tracking score evolution, monitoring calculation activity, and building real-time applications.
Events are stored on the blockchain and can be efficiently queried by indexers. They provide a reliable audit trail for all score changes and system updates.

Score Events

ScoreCalculated

Emitted when a new score is calculated for a user.
event ScoreCalculated(
    address indexed user,
    uint256 totalScore,
    uint256 timestamp
);
Parameters:
  • user (address indexed): The user whose score was calculated
  • totalScore (uint256): The calculated total score (0-1000)
  • timestamp (uint256): Block timestamp of calculation
When Emitted:
  • When calculateScore() is called
  • During batch score calculations
  • When scores are automatically refreshed
Example Usage:
// Listen for score calculation events
contract.on('ScoreCalculated', (user, totalScore, timestamp, event) => {
  console.log(`Score calculated for ${user}: ${totalScore.toString()}`);
  console.log(`Timestamp: ${new Date(timestamp.toNumber() * 1000).toISOString()}`);
  console.log(`Block: ${event.blockNumber}`);
});

// Filter for specific user
const filter = contract.filters.ScoreCalculated('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
contract.on(filter, (user, totalScore, timestamp, event) => {
  console.log(`Alice's score updated: ${totalScore.toString()}`);
});

// Get historical score calculations
async function getScoreHistory(userAddress) {
  const filter = contract.filters.ScoreCalculated(userAddress);
  const events = await contract.queryFilter(filter);
  
  return events.map(event => ({
    score: event.args.totalScore.toString(),
    timestamp: event.args.timestamp.toNumber(),
    blockNumber: event.blockNumber,
    transactionHash: event.transactionHash
  }));
}

ScoreUpdated

Emitted when a user’s score changes.
event ScoreUpdated(
    address indexed user,
    uint256 oldScore,
    uint256 newScore
);
Parameters:
  • user (address indexed): The user whose score changed
  • oldScore (uint256): Previous score value
  • newScore (uint256): New score value
When Emitted:
  • When score recalculation results in a different value
  • After category score updates
  • During manual score refreshes
Example Usage:
// Monitor score changes
contract.on('ScoreUpdated', (user, oldScore, newScore, event) => {
  const change = newScore.sub(oldScore);
  const direction = change.isNegative() ? 'decreased' : 'increased';
  
  console.log(`Score ${direction} for ${user}`);
  console.log(`Old: ${oldScore.toString()}, New: ${newScore.toString()}`);
  console.log(`Change: ${Math.abs(change.toNumber())}`);
});

// Track score improvements
async function trackScoreImprovements() {
  const filter = contract.filters.ScoreUpdated();
  const events = await contract.queryFilter(filter);
  
  const improvements = events.filter(event => 
    event.args.newScore.gt(event.args.oldScore)
  );
  
  console.log(`${improvements.length} score improvements detected`);
  return improvements;
}

CategoryScoreUpdated

Emitted when a category score is updated.
event CategoryScoreUpdated(
    address indexed user,
    uint8 indexed category,
    uint256 score
);
Parameters:
  • user (address indexed): The user whose category score was updated
  • category (uint8 indexed): Category index (0-7)
  • score (uint256): New category score (0-1000)
Category Mapping:
  • 0: DeFi
  • 1: NFT
  • 2: Social
  • 3: Trading
  • 4: Governance
  • 5: Gaming
  • 6: Identity
  • 7: Trust
When Emitted:
  • When updateCategoryScore() is called
  • During batch category updates
  • When individual category recalculation occurs
Example Usage:
// Monitor category score updates
const categories = ['DeFi', 'NFT', 'Social', 'Trading', 'Governance', 'Gaming', 'Identity', 'Trust'];

contract.on('CategoryScoreUpdated', (user, category, score, event) => {
  console.log(`${categories[category]} score for ${user}: ${score.toString()}`);
});

// Track DeFi score updates
const defiFilter = contract.filters.CategoryScoreUpdated(null, 0); // 0 = DeFi
contract.on(defiFilter, (user, category, score, event) => {
  console.log(`DeFi score updated for ${user}: ${score.toString()}`);
});

// Get category score history
async function getCategoryHistory(userAddress, category) {
  const filter = contract.filters.CategoryScoreUpdated(userAddress, category);
  const events = await contract.queryFilter(filter);
  
  return events.map(event => ({
    category: categories[event.args.category],
    score: event.args.score.toString(),
    blockNumber: event.blockNumber,
    timestamp: event.args.timestamp
  }));
}

Configuration Events

CategoryWeightUpdated

Emitted when a category weight is changed.
event CategoryWeightUpdated(
    uint8 indexed category,
    uint256 oldWeight,
    uint256 newWeight
);
Parameters:
  • category (uint8 indexed): Category index (0-7)
  • oldWeight (uint256): Previous weight in basis points
  • newWeight (uint256): New weight in basis points
When Emitted:
  • When updateCategoryWeight() is called
  • During batch weight updates
  • When category weights are reconfigured
Example Usage:
// Monitor weight changes
contract.on('CategoryWeightUpdated', (category, oldWeight, newWeight, event) => {
  const categories = ['DeFi', 'NFT', 'Social', 'Trading', 'Governance', 'Gaming', 'Identity', 'Trust'];
  
  console.log(`${categories[category]} weight changed`);
  console.log(`Old: ${oldWeight.toNumber() / 100}%`);
  console.log(`New: ${newWeight.toNumber() / 100}%`);
});

// Get all weight changes
async function getWeightChanges() {
  const filter = contract.filters.CategoryWeightUpdated();
  const events = await contract.queryFilter(filter);
  
  return events.map(event => ({
    category: event.args.category,
    oldWeight: event.args.oldWeight.toNumber() / 100,
    newWeight: event.args.newWeight.toNumber() / 100,
    blockNumber: event.blockNumber
  }));
}

CalculatorConfigured

Emitted when the calculator is configured or reconfigured.
event CalculatorConfigured(
    address indexed admin,
    uint256 timestamp
);
Parameters:
  • admin (address indexed): Admin who performed the configuration
  • timestamp (uint256): Configuration timestamp
When Emitted:
  • During initial deployment configuration
  • When major configuration changes occur
  • When admin reconfigures the calculator

Event Monitoring

Real-time Score Tracking

// Comprehensive score monitoring
class ScoreMonitor {
  constructor(contract) {
    this.contract = contract;
    this.scoreHistory = new Map();
    this.setupListeners();
  }
  
  setupListeners() {
    // Track all score calculations
    this.contract.on('ScoreCalculated', (user, totalScore, timestamp, event) => {
      this.recordScore(user, totalScore, timestamp, event);
    });
    
    // Track score updates
    this.contract.on('ScoreUpdated', (user, oldScore, newScore, event) => {
      this.recordScoreChange(user, oldScore, newScore, event);
    });
    
    // Track category updates
    this.contract.on('CategoryScoreUpdated', (user, category, score, event) => {
      this.recordCategoryUpdate(user, category, score, event);
    });
  }
  
  recordScore(user, totalScore, timestamp, event) {
    if (!this.scoreHistory.has(user)) {
      this.scoreHistory.set(user, []);
    }
    
    this.scoreHistory.get(user).push({
      score: totalScore.toString(),
      timestamp: timestamp.toNumber(),
      blockNumber: event.blockNumber,
      type: 'calculated'
    });
    
    console.log(`Score calculated: ${user} - ${totalScore.toString()}`);
  }
  
  recordScoreChange(user, oldScore, newScore, event) {
    const change = newScore.sub(oldScore).toNumber();
    const percentChange = ((change / oldScore.toNumber()) * 100).toFixed(2);
    
    console.log(`Score changed: ${user}`);
    console.log(`  ${oldScore.toString()}${newScore.toString()}`);
    console.log(`  Change: ${change} (${percentChange}%)`);
  }
  
  recordCategoryUpdate(user, category, score, event) {
    const categories = ['DeFi', 'NFT', 'Social', 'Trading', 'Governance', 'Gaming', 'Identity', 'Trust'];
    console.log(`${categories[category]} updated: ${user} - ${score.toString()}`);
  }
  
  getUserHistory(user) {
    return this.scoreHistory.get(user) || [];
  }
  
  getTopPerformers(limit = 10) {
    const performers = [];
    
    for (const [user, history] of this.scoreHistory.entries()) {
      if (history.length > 0) {
        const latestScore = parseInt(history[history.length - 1].score);
        performers.push({ user, score: latestScore });
      }
    }
    
    return performers.sort((a, b) => b.score - a.score).slice(0, limit);
  }
}

// Usage
const monitor = new ScoreMonitor(contract);

Event Analytics

// Analyze score trends
async function analyzeScoreTrends() {
  const currentBlock = await provider.getBlockNumber();
  const startBlock = currentBlock - 100000; // Last 100k blocks
  
  const filter = contract.filters.ScoreCalculated();
  const events = await contract.queryFilter(filter, startBlock, currentBlock);
  
  const analytics = {
    totalCalculations: events.length,
    uniqueUsers: new Set(events.map(e => e.args.user)).size,
    averageScore: 0,
    scoreDistribution: { low: 0, medium: 0, high: 0 },
    topScorers: []
  };
  
  // Calculate average
  const totalScore = events.reduce((sum, e) => sum + e.args.totalScore.toNumber(), 0);
  analytics.averageScore = totalScore / events.length;
  
  // Distribution
  events.forEach(event => {
    const score = event.args.totalScore.toNumber();
    if (score < 300) analytics.scoreDistribution.low++;
    else if (score < 700) analytics.scoreDistribution.medium++;
    else analytics.scoreDistribution.high++;
  });
  
  // Top scorers
  const userScores = new Map();
  events.forEach(event => {
    userScores.set(event.args.user, event.args.totalScore.toNumber());
  });
  
  analytics.topScorers = Array.from(userScores.entries())
    .sort((a, b) => b[1] - a[1])
    .slice(0, 10)
    .map(([user, score]) => ({ user, score }));
  
  return analytics;
}

Best Practices

Event Handling

  1. Use Indexed Parameters: Filter events efficiently using indexed parameters
  2. Batch Processing: Process multiple events in batches
  3. Error Handling: Implement robust error handling for event listeners
  4. Performance: Limit block ranges for large queries
  5. Storage: Store important event data in a database

Monitoring Strategy

  1. Real-time Alerts: Set up alerts for significant score changes
  2. Historical Analysis: Regularly analyze historical event data
  3. User Tracking: Track individual user score evolution
  4. System Health: Monitor event emission rates
  5. Anomaly Detection: Detect unusual score patterns