Skip to main content

Overview

This guide provides comprehensive examples for integrating with the ZKScore Trust Registry contract. It covers attestation creation, verification workflows, trust score calculation, and best practices for production deployments.
Always test your integration on testnet before deploying to mainnet. Use the testnet contract addresses provided in the Contract Overview section.

Web3 Integration

Basic Setup

import { ethers } from 'ethers';

// Contract configuration
const TRUST_REGISTRY_ADDRESS = '0x4567890123456789012345678901234567890123';
const SCHEMA_REGISTRY_ADDRESS = '0x6789012345678901234567890123456789012345';

// Initialize provider
const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');

// Initialize contracts
const trustRegistry = new ethers.Contract(
  TRUST_REGISTRY_ADDRESS,
  TRUST_REGISTRY_ABI,
  provider
);

const schemaRegistry = new ethers.Contract(
  SCHEMA_REGISTRY_ADDRESS,
  SCHEMA_REGISTRY_ABI,
  provider
);

// For transactions
const signer = provider.getSigner();
const trustRegistryWithSigner = trustRegistry.connect(signer);

Integration Class

class TrustRegistryIntegration {
  constructor(provider, registryAddress, abi) {
    this.provider = provider;
    this.contract = new ethers.Contract(registryAddress, abi, provider);
    this.contractWithSigner = null;
    this.schemaCache = new Map();
  }
  
  setSigner(signer) {
    this.contractWithSigner = this.contract.connect(signer);
  }
  
  // Register a new schema
  async registerSchema(definition, revocable = true) {
    if (!this.contractWithSigner) {
      throw new Error('Signer not set');
    }
    
    try {
      const tx = await this.contractWithSigner.registerSchema(
        definition,
        ethers.constants.AddressZero, // No resolver
        revocable
      );
      
      const receipt = await tx.wait();
      const event = receipt.events.find(e => e.event === 'SchemaRegistered');
      const schemaUID = event.args.uid;
      
      // Cache schema
      this.schemaCache.set(schemaUID, { definition, revocable });
      
      return {
        success: true,
        schemaUID,
        definition,
        revocable,
        transactionHash: receipt.transactionHash
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
  
  // Create attestation
  async attest(recipient, schemaUID, data, expirationTime = 0) {
    if (!this.contractWithSigner) {
      throw new Error('Signer not set');
    }
    
    try {
      const attestationRequest = {
        schema: schemaUID,
        data: {
          recipient,
          expirationTime,
          revocable: true,
          refUID: ethers.constants.HashZero,
          data
        }
      };
      
      const tx = await this.contractWithSigner.attest(attestationRequest);
      const receipt = await tx.wait();
      
      const event = receipt.events.find(e => e.event === 'Attested');
      
      return {
        success: true,
        uid: event.args.uid,
        recipient: event.args.recipient,
        attester: event.args.attester,
        schema: event.args.schema,
        transactionHash: receipt.transactionHash
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
  
  // Get attestation
  async getAttestation(uid) {
    try {
      const attestation = await this.contract.getAttestation(uid);
      
      return {
        success: true,
        attestation: {
          uid: attestation.uid,
          schema: attestation.schema,
          attester: attestation.attester,
          recipient: attestation.recipient,
          time: attestation.time,
          expirationTime: attestation.expirationTime,
          revocable: attestation.revocable,
          revoked: attestation.revoked,
          data: attestation.data
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
  
  // Get user attestations
  async getUserAttestations(address, schemaUID = ethers.constants.HashZero) {
    try {
      const uids = await this.contract.getReceivedAttestationUIDs(
        address,
        schemaUID,
        0,
        100,
        true
      );
      
      const attestations = await Promise.all(
        uids.map(uid => this.getAttestation(uid))
      );
      
      return {
        success: true,
        count: uids.length,
        attestations: attestations
          .filter(a => a.success)
          .map(a => a.attestation)
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
  
  // Verify attestation validity
  async isValid(uid) {
    try {
      const isValid = await this.contract.isAttestationValid(uid);
      
      return {
        success: true,
        isValid
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
}

// Usage
const integration = new TrustRegistryIntegration(
  provider,
  TRUST_REGISTRY_ADDRESS,
  TRUST_REGISTRY_ABI
);

integration.setSigner(signer);

// Register schema
const schemaResult = await integration.registerSchema(
  "bool verified,uint256 level,uint256 timestamp"
);
console.log('Schema:', schemaResult);

// Create attestation
const attestResult = await integration.attest(
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  schemaResult.schemaUID,
  ethers.utils.defaultAbiCoder.encode(
    ['bool', 'uint256', 'uint256'],
    [true, 5, Math.floor(Date.now() / 1000)]
  )
);
console.log('Attestation:', attestResult);

Complete Trust System

Trust Score Dashboard

class TrustDashboard {
  constructor(integration) {
    this.integration = integration;
    this.attestationCache = new Map();
  }
  
  // Get complete trust profile
  async getTrustProfile(address) {
    try {
      // Get all attestations
      const attestationsResult = await this.integration.getUserAttestations(address);
      
      if (!attestationsResult.success) {
        throw new Error(attestationsResult.error);
      }
      
      const attestations = attestationsResult.attestations;
      
      // Calculate trust metrics
      const metrics = {
        totalAttestations: attestations.length,
        activeAttestations: attestations.filter(a => !a.revoked).length,
        revokedAttestations: attestations.filter(a => a.revoked).length,
        uniqueAttesters: new Set(attestations.map(a => a.attester)).size,
        schemaDistribution: this.getSchemaDistribution(attestations),
        oldestAttestation: this.getOldest(attestations),
        newestAttestation: this.getNewest(attestations)
      };
      
      // Calculate trust score
      const trustScore = this.calculateTrustScore(attestations);
      
      return {
        success: true,
        address,
        metrics,
        trustScore,
        attestations
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
  
  getSchemaDistribution(attestations) {
    const distribution = {};
    
    attestations.forEach(a => {
      const schema = a.schema;
      distribution[schema] = (distribution[schema] || 0) + 1;
    });
    
    return distribution;
  }
  
  getOldest(attestations) {
    if (attestations.length === 0) return null;
    return attestations.reduce((oldest, a) => 
      a.time < oldest.time ? a : oldest
    );
  }
  
  getNewest(attestations) {
    if (attestations.length === 0) return null;
    return attestations.reduce((newest, a) => 
      a.time > newest.time ? a : newest
    );
  }
  
  calculateTrustScore(attestations) {
    const active = attestations.filter(a => !a.revoked);
    
    // Base score from attestation count
    let score = Math.min(active.length * 100, 500);
    
    // Bonus for unique attesters
    const uniqueAttesters = new Set(active.map(a => a.attester)).size;
    score += Math.min(uniqueAttesters * 50, 300);
    
    // Bonus for age (older attestations = more trust)
    const now = Math.floor(Date.now() / 1000);
    const avgAge = active.reduce((sum, a) => sum + (now - a.time), 0) / active.length;
    const ageBonus = Math.min((avgAge / (30 * 24 * 60 * 60)) * 100, 200); // Max 200 for 30+ days
    score += ageBonus;
    
    return Math.min(Math.round(score), 1000);
  }
}

// Usage
const dashboard = new TrustDashboard(integration);

const profile = await dashboard.getTrustProfile('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
console.log('Trust Profile:', profile);
console.log(`Trust Score: ${profile.trustScore}/1000`);
console.log(`Active Attestations: ${profile.metrics.activeAttestations}`);

Attestation Workflows

Identity Verification Workflow

class IdentityVerificationWorkflow {
  constructor(integration, schemaUID) {
    this.integration = integration;
    this.schemaUID = schemaUID;
  }
  
  // Step 1: Request verification
  async requestVerification(address, verificationData) {
    console.log(`Verification requested for ${address}`);
    
    // In production, this would trigger off-chain verification
    return {
      requestId: ethers.utils.id(`${address}-${Date.now()}`),
      status: 'pending',
      address,
      verificationData
    };
  }
  
  // Step 2: Complete verification (called by verifier)
  async completeVerification(address, verified, level) {
    try {
      // Encode attestation data
      const attestationData = ethers.utils.defaultAbiCoder.encode(
        ['bool', 'uint256', 'uint256'],
        [verified, level, Math.floor(Date.now() / 1000)]
      );
      
      // Create attestation
      const result = await this.integration.attest(
        address,
        this.schemaUID,
        attestationData
      );
      
      if (result.success) {
        console.log(`✅ Verification complete for ${address}`);
        console.log(`Attestation UID: ${result.uid}`);
      }
      
      return result;
    } catch (error) {
      console.error('Verification failed:', error.message);
      throw error;
    }
  }
  
  // Step 3: Check verification status
  async checkVerification(address) {
    try {
      const attestations = await this.integration.getUserAttestations(
        address,
        this.schemaUID
      );
      
      if (!attestations.success) {
        return {
          verified: false,
          level: 0,
          attestationCount: 0
        };
      }
      
      const activeAttestations = attestations.attestations.filter(a => !a.revoked);
      
      if (activeAttestations.length === 0) {
        return {
          verified: false,
          level: 0,
          attestationCount: 0
        };
      }
      
      // Decode latest attestation
      const latest = activeAttestations[0];
      const [verified, level] = ethers.utils.defaultAbiCoder.decode(
        ['bool', 'uint256', 'uint256'],
        latest.data
      );
      
      return {
        verified,
        level: level.toNumber(),
        attestationCount: activeAttestations.length,
        latestUID: latest.uid
      };
    } catch (error) {
      console.error('Check failed:', error.message);
      return {
        verified: false,
        level: 0,
        attestationCount: 0,
        error: error.message
      };
    }
  }
}

// Usage
const verificationWorkflow = new IdentityVerificationWorkflow(
  integration,
  schemaUID
);

// Request verification
const request = await verificationWorkflow.requestVerification(
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  { email: 'user@example.com', phone: '+1234567890' }
);

// Complete verification
const result = await verificationWorkflow.completeVerification(
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  true,
  5
);

// Check status
const status = await verificationWorkflow.checkVerification(
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'
);
console.log('Verification Status:', status);

Error Handling

class TrustRegistryErrorHandler {
  static handleError(error) {
    const errorMessage = error.message || error.toString();
    
    if (errorMessage.includes('InvalidSchema')) {
      return {
        type: 'INVALID_SCHEMA',
        message: 'Schema does not exist. Please register it first.',
        code: 'TR001'
      };
    }
    
    if (errorMessage.includes('NotAttester')) {
      return {
        type: 'NOT_ATTESTER',
        message: 'Only the attester can perform this action.',
        code: 'TR002'
      };
    }
    
    if (errorMessage.includes('NotRevocable')) {
      return {
        type: 'NOT_REVOCABLE',
        message: 'This attestation cannot be revoked.',
        code: 'TR003'
      };
    }
    
    if (errorMessage.includes('AlreadyRevoked')) {
      return {
        type: 'ALREADY_REVOKED',
        message: 'Attestation has already been revoked.',
        code: 'TR004'
      };
    }
    
    if (errorMessage.includes('Expired')) {
      return {
        type: 'EXPIRED',
        message: 'Attestation has expired.',
        code: 'TR005'
      };
    }
    
    return {
      type: 'UNKNOWN_ERROR',
      message: errorMessage,
      code: 'TR999'
    };
  }
  
  static async safeExecute(operation, retries = 3) {
    for (let attempt = 1; attempt <= retries; attempt++) {
      try {
        return await operation();
      } catch (error) {
        const errorInfo = this.handleError(error);
        
        if (attempt === retries) {
          throw errorInfo;
        }
        
        await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt - 1)));
      }
    }
  }
}

// Usage
try {
  const result = await TrustRegistryErrorHandler.safeExecute(async () => {
    return await integration.attest(recipient, schemaUID, data);
  });
  console.log('Success:', result);
} catch (error) {
  console.error(`Error [${error.code}]:`, error.message);
}

Best Practices

Security

  1. Verify Attestations: Always check validity before trusting
  2. Attester Reputation: Consider attester trustworthiness
  3. Schema Validation: Use well-defined schemas
  4. Expiration: Set appropriate expiration times
  5. Revocation: Monitor for revocations

Performance

  1. Batch Operations: Use multiAttest for multiple attestations
  2. Cache Schemas: Cache schema definitions locally
  3. Event Listening: Use events for real-time updates
  4. Pagination: Paginate large attestation lists
  5. Gas Optimization: Estimate gas before transactions

Integration

  1. Test Thoroughly: Test on testnet first
  2. Error Handling: Implement comprehensive error handling
  3. Monitor Events: Track all attestation events
  4. Documentation: Document your attestation schemas
  5. User Experience: Provide clear feedback to users