Skip to main content

Documentation Index

Fetch the complete documentation index at: https://core.anylayer.org/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The ZKScore Trust Registry contract emits events for all attestation lifecycle activities, schema registration, and trust score updates. These events enable real-time monitoring and off-chain indexing of the trust graph.
Events provide a complete audit trail of all trust-related activities and are essential for building trust analytics and reputation systems.

Attestation Events

Attested

Emitted when a new attestation is created.
event Attested(
    address indexed recipient,
    address indexed attester,
    bytes32 uid,
    bytes32 indexed schema
);
Parameters:
  • recipient (address indexed): Attestation recipient
  • attester (address indexed): Who created the attestation
  • uid (bytes32): Unique attestation identifier
  • schema (bytes32 indexed): Schema used
When Emitted:
  • When attest() is successfully called
  • During batch attestation operations
Example Usage:
// Listen for attestations
contract.on('Attested', (recipient, attester, uid, schema, event) => {
  console.log('New Attestation:');
  console.log(`  Recipient: ${recipient}`);
  console.log(`  Attester: ${attester}`);
  console.log(`  UID: ${uid}`);
  console.log(`  Schema: ${schema}`);
  console.log(`  Block: ${event.blockNumber}`);
});

// Filter for specific recipient
const recipientFilter = contract.filters.Attested('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
contract.on(recipientFilter, (recipient, attester, uid, schema) => {
  console.log(`Alice received attestation: ${uid}`);
});

// Get attestation history
async function getAttestationHistory(recipient) {
  const filter = contract.filters.Attested(recipient);
  const events = await contract.queryFilter(filter);
  
  return events.map(e => ({
    recipient: e.args.recipient,
    attester: e.args.attester,
    uid: e.args.uid,
    schema: e.args.schema,
    blockNumber: e.blockNumber,
    timestamp: e.args.timestamp
  }));
}

Revoked

Emitted when an attestation is revoked.
event Revoked(
    address indexed recipient,
    address indexed attester,
    bytes32 uid,
    bytes32 indexed schema
);
Parameters:
  • recipient (address indexed): Original attestation recipient
  • attester (address indexed): Who revoked the attestation
  • uid (bytes32): Attestation identifier
  • schema (bytes32 indexed): Schema used
When Emitted:
  • When revoke() is successfully called
  • During batch revocation operations
Example Usage:
// Monitor revocations
contract.on('Revoked', (recipient, attester, uid, schema, event) => {
  console.log(`Attestation ${uid} revoked by ${attester}`);
});

// Track revocations for specific schema
const schemaFilter = contract.filters.Revoked(null, null, null, schemaUID);
contract.on(schemaFilter, (recipient, attester, uid, schema) => {
  console.log(`Schema ${schema} attestation revoked: ${uid}`);
});

Schema Events

SchemaRegistered

Emitted when a new schema is registered.
event SchemaRegistered(
    bytes32 indexed uid,
    address indexed registerer
);
Parameters:
  • uid (bytes32 indexed): Schema unique identifier
  • registerer (address indexed): Who registered the schema
When Emitted:
  • When registerSchema() is successfully called
Example Usage:
// Monitor schema registrations
contract.on('SchemaRegistered', async (uid, registerer, event) => {
  console.log('New Schema Registered:');
  console.log(`  UID: ${uid}`);
  console.log(`  Registerer: ${registerer}`);
  
  // Get schema details
  const schema = await contract.getSchema(uid);
  console.log(`  Definition: ${schema.schema}`);
  console.log(`  Revocable: ${schema.revocable}`);
});

// Get all registered schemas
async function getAllSchemas() {
  const filter = contract.filters.SchemaRegistered();
  const events = await contract.queryFilter(filter);
  
  const schemas = await Promise.all(
    events.map(async e => {
      const schema = await contract.getSchema(e.args.uid);
      return {
        uid: e.args.uid,
        registerer: e.args.registerer,
        definition: schema.schema,
        revocable: schema.revocable,
        blockNumber: e.blockNumber
      };
    })
  );
  
  return schemas;
}

Trust Module Events

TrustModuleRegistered

Emitted when a trust evaluation module is registered.
event TrustModuleRegistered(
    address indexed module,
    string name
);
Parameters:
  • module (address indexed): Module contract address
  • name (string): Module name
When Emitted:
  • When a new trust module is registered

TrustScoreUpdated

Emitted when a user’s trust score changes.
event TrustScoreUpdated(
    address indexed subject,
    uint256 oldScore,
    uint256 newScore
);
Parameters:
  • subject (address indexed): User whose score changed
  • oldScore (uint256): Previous trust score
  • newScore (uint256): New trust score
When Emitted:
  • When trust score is recalculated
  • After attestation creation/revocation

Event Monitoring

Comprehensive Trust Monitor

class TrustEventMonitor {
  constructor(contract) {
    this.contract = contract;
    this.attestations = new Map();
    this.schemas = new Map();
    this.trustScores = new Map();
    this.setupListeners();
  }
  
  setupListeners() {
    // Monitor attestations
    this.contract.on('Attested', (recipient, attester, uid, schema, event) => {
      this.handleAttested(recipient, attester, uid, schema, event);
    });
    
    // Monitor revocations
    this.contract.on('Revoked', (recipient, attester, uid, schema, event) => {
      this.handleRevoked(recipient, attester, uid, schema, event);
    });
    
    // Monitor schemas
    this.contract.on('SchemaRegistered', (uid, registerer, event) => {
      this.handleSchemaRegistered(uid, registerer, event);
    });
    
    // Monitor trust scores
    this.contract.on('TrustScoreUpdated', (subject, oldScore, newScore, event) => {
      this.handleTrustScoreUpdated(subject, oldScore, newScore, event);
    });
  }
  
  handleAttested(recipient, attester, uid, schema, event) {
    const attestation = {
      recipient,
      attester,
      uid,
      schema,
      blockNumber: event.blockNumber,
      timestamp: event.args.timestamp
    };
    
    // Store attestation
    this.attestations.set(uid, attestation);
    
    // Update recipient's attestation list
    if (!this.recipientAttestations.has(recipient)) {
      this.recipientAttestations.set(recipient, []);
    }
    this.recipientAttestations.get(recipient).push(uid);
    
    console.log(`✅ New attestation: ${uid.slice(0, 10)}... for ${recipient.slice(0, 10)}...`);
    
    // Trigger analytics update
    this.updateAnalytics(recipient);
  }
  
  handleRevoked(recipient, attester, uid, schema, event) {
    const attestation = this.attestations.get(uid);
    if (attestation) {
      attestation.revoked = true;
      attestation.revokedAt = event.blockNumber;
    }
    
    console.log(`❌ Attestation revoked: ${uid.slice(0, 10)}...`);
    
    // Update analytics
    this.updateAnalytics(recipient);
  }
  
  handleSchemaRegistered(uid, registerer, event) {
    this.schemas.set(uid, {
      uid,
      registerer,
      blockNumber: event.blockNumber
    });
    
    console.log(`📋 New schema registered: ${uid.slice(0, 10)}...`);
  }
  
  handleTrustScoreUpdated(subject, oldScore, newScore, event) {
    this.trustScores.set(subject, {
      score: newScore.toString(),
      previousScore: oldScore.toString(),
      updatedAt: event.blockNumber
    });
    
    const change = newScore.sub(oldScore);
    const direction = change.isNegative() ? '📉' : '📈';
    
    console.log(`${direction} Trust score updated for ${subject.slice(0, 10)}...`);
    console.log(`  Old: ${oldScore.toString()}, New: ${newScore.toString()}`);
  }
  
  updateAnalytics(address) {
    // Calculate analytics
    const attestations = this.recipientAttestations.get(address) || [];
    const activeAttestations = attestations.filter(uid => {
      const att = this.attestations.get(uid);
      return att && !att.revoked;
    });
    
    console.log(`📊 ${address.slice(0, 10)}... has ${activeAttestations.length} active attestations`);
  }
  
  getStats() {
    return {
      totalAttestations: this.attestations.size,
      totalSchemas: this.schemas.size,
      trackedUsers: this.trustScores.size
    };
  }
  
  getRecipientStats(address) {
    const attestations = this.recipientAttestations.get(address) || [];
    const active = attestations.filter(uid => {
      const att = this.attestations.get(uid);
      return att && !att.revoked;
    });
    
    return {
      total: attestations.length,
      active: active.length,
      revoked: attestations.length - active.length,
      trustScore: this.trustScores.get(address)?.score || '0'
    };
  }
}

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

// Get overall stats
console.log('Trust Registry Stats:', monitor.getStats());

// Get stats for specific user
const userStats = monitor.getRecipientStats('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
console.log('User Stats:', userStats);

Event Analytics

Trust Graph Analysis

async function analyzeTrustGraph() {
  const currentBlock = await provider.getBlockNumber();
  const startBlock = currentBlock - 100000;
  
  // Get all attestations
  const attestedFilter = contract.filters.Attested();
  const attestedEvents = await contract.queryFilter(attestedFilter, startBlock);
  
  // Get all revocations
  const revokedFilter = contract.filters.Revoked();
  const revokedEvents = await contract.queryFilter(revokedFilter, startBlock);
  
  const analytics = {
    totalAttestations: attestedEvents.length,
    totalRevocations: revokedEvents.length,
    uniqueAttesters: new Set(attestedEvents.map(e => e.args.attester)).size,
    uniqueRecipients: new Set(attestedEvents.map(e => e.args.recipient)).size,
    topAttesters: getTopAttesters(attestedEvents),
    mostAttestedUsers: getMostAttestedUsers(attestedEvents, revokedEvents),
    schemaDistribution: getSchemaDistribution(attestedEvents)
  };
  
  return analytics;
}

function getTopAttesters(events) {
  const counts = {};
  events.forEach(e => {
    counts[e.args.attester] = (counts[e.args.attester] || 0) + 1;
  });
  
  return Object.entries(counts)
    .sort(([,a], [,b]) => b - a)
    .slice(0, 10)
    .map(([attester, count]) => ({ attester, count }));
}

function getMostAttestedUsers(attestedEvents, revokedEvents) {
  const counts = {};
  
  attestedEvents.forEach(e => {
    counts[e.args.recipient] = (counts[e.args.recipient] || 0) + 1;
  });
  
  revokedEvents.forEach(e => {
    counts[e.args.recipient] = (counts[e.args.recipient] || 0) - 1;
  });
  
  return Object.entries(counts)
    .sort(([,a], [,b]) => b - a)
    .slice(0, 10)
    .map(([recipient, count]) => ({ recipient, activeAttestations: count }));
}

function getSchemaDistribution(events) {
  const counts = {};
  events.forEach(e => {
    counts[e.args.schema] = (counts[e.args.schema] || 0) + 1;
  });
  
  return Object.entries(counts)
    .map(([schema, count]) => ({ schema, count }))
    .sort((a, b) => b.count - a.count);
}

Best Practices

Event Handling

  1. Use Indexed Parameters: Filter efficiently using indexed fields
  2. Store Event Data: Cache important events off-chain
  3. Monitor Continuously: Set up real-time listeners
  4. Handle Reorgs: Account for blockchain reorganizations
  5. Rate Limiting: Don’t overwhelm with event processing

Performance

  1. Limit Block Ranges: Query smaller ranges to avoid timeouts
  2. Pagination: Implement pagination for large datasets
  3. Batch Processing: Process events in batches
  4. Caching: Cache frequently accessed event data
  5. Indexing: Use subgraphs or custom indexers