Skip to main content

What is Verification?

Verification is the process of validating attestations to confirm their authenticity, authority legitimacy, and data integrity. It’s the mechanism that transforms attestations from simple data into trusted, actionable information. In traditional systems, verification might involve:
  • Calling an institution to confirm a credential
  • Checking a database for license validity
  • Cross-referencing multiple sources for accuracy
  • Validating signatures and seals on documents
AttestProtocol automates and cryptographically secures this process, enabling instant, trustless verification.

Verification Components

Core Validation Checks

Every verification process includes these fundamental checks:

Cryptographic Integrity

Verify the attestation’s digital signature and ensure data hasn’t been tampered with

Authority Validation

Confirm the issuing authority has permission to create attestations for this schema

Schema Compliance

Ensure attestation data conforms to the specified schema structure and types

Status Verification

Check expiration dates, revocation status, and temporal validity

Advanced Verification Features

Verify attestations that require consensus from multiple authorities for enhanced trust.
Check attestation validity at specific points in time, useful for audit trails and compliance.
Apply complex business rules and conditional verification based on multiple attestation factors.
Efficiently verify multiple attestations simultaneously for performance optimization.

Verification Methods

Basic Boolean Verification

Simple true/false checks for attestation existence and validity:
// Check if user has valid KYC
const isVerified = await sdk.fetchAttestation({
  schemaUID: 'kyc-basic-v1',
  subject: userAddress
});

if (isVerified.data && !isVerified.data.revoked) {
  console.log('User has valid KYC attestation');
  // Proceed with restricted actions
}

Detailed Verification

Retrieve complete attestation data for analysis:
// Get full attestation details
const attestation = await sdk.fetchAttestation({
  schemaUID: 'professional-cert-v1',
  subject: userAddress
});

if (attestation.data) {
  const certData = parseAttestationData(attestation.data.value);
  
  console.log('Certificate:', certData.title);
  console.log('Issuer:', certData.issuer);
  console.log('Valid Until:', new Date(certData.validUntil * 1000));
  console.log('Authority:', attestation.data.attester);
}

Conditional Verification

Apply business logic during verification:
async function verifyTradingEligibility(userAddress: string, tradeAmount: number) {
  // Basic KYC required for all trades
  const basicKYC = await sdk.fetchAttestation({
    schemaUID: 'kyc-basic-v1',
    subject: userAddress
  });

  if (!basicKYC.data || basicKYC.data.revoked) {
    return { allowed: false, reason: 'KYC verification required' };
  }

  // Enhanced KYC required for large trades
  if (tradeAmount > 50000) {
    const enhancedKYC = await sdk.fetchAttestation({
      schemaUID: 'kyc-enhanced-v1',
      subject: userAddress
    });

    if (!enhancedKYC.data || enhancedKYC.data.revoked) {
      return { allowed: false, reason: 'Enhanced KYC required for large trades' };
    }
  }

  // Check sanctions screening for international trades
  const sanctionsCheck = await sdk.fetchAttestation({
    schemaUID: 'sanctions-screening-v1',
    subject: userAddress
  });

  if (!sanctionsCheck.data) {
    return { allowed: false, reason: 'Sanctions screening required' };
  }

  return { allowed: true, reason: 'All verifications passed' };
}

Verification Patterns

Single Authority Verification

Verify attestations from a specific trusted authority:
async function verifyFromTrustedAuthority(
  subject: string,
  schema: string,
  trustedAuthority: string
) {
  const attestation = await sdk.fetchAttestation({
    schemaUID: schema,
    subject: subject
  });

  return (
    attestation.data &&
    !attestation.data.revoked &&
    attestation.data.attester === trustedAuthority
  );
}

Multi-Authority Consensus

Require agreement from multiple authorities:
async function verifyMultiAuthorityConsensus(
  subject: string,
  schema: string,
  requiredAuthorities: string[],
  threshold: number = requiredAuthorities.length
) {
  const verifications = await Promise.all(
    requiredAuthorities.map(async (authority) => {
      const attestation = await sdk.fetchAttestation({
        schemaUID: schema,
        subject: subject
      });

      return attestation.data &&
             !attestation.data.revoked &&
             attestation.data.attester === authority;
    })
  );

  const validCount = verifications.filter(Boolean).length;
  return validCount >= threshold;
}

Hierarchical Verification

Verify attestations in order of trust hierarchy:
async function verifyHierarchical(
  subject: string,
  schemas: string[]
) {
  for (const schema of schemas) {
    const attestation = await sdk.fetchAttestation({
      schemaUID: schema,
      subject: subject
    });

    if (attestation.data && !attestation.data.revoked) {
      return {
        verified: true,
        level: schema,
        attestation: attestation.data
      };
    }
  }

  return { verified: false, level: null };
}

// Usage: Check from highest to lowest trust level
const result = await verifyHierarchical(userAddress, [
  'kyc-institutional-v1',  // Highest
  'kyc-enhanced-v1',       // Medium
  'kyc-basic-v1'           // Basic
]);

Performance Optimization

Caching Strategies

Implement smart caching for frequently verified attestations:
class VerificationCache {
  private cache = new Map<string, { data: any; timestamp: number }>();
  private ttl = 5 * 60 * 1000; // 5 minutes

  async verifyWithCache(schemaUID: string, subject: string) {
    const key = `${schemaUID}:${subject}`;
    const cached = this.cache.get(key);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }

    const result = await sdk.fetchAttestation({ schemaUID, subject });
    
    this.cache.set(key, {
      data: result,
      timestamp: Date.now()
    });

    return result;
  }
}

Batch Verification

Verify multiple attestations efficiently:
async function batchVerify(verifications: Array<{schema: string, subject: string}>) {
  const results = await Promise.all(
    verifications.map(async (v) => {
      try {
        const attestation = await sdk.fetchAttestation({
          schemaUID: v.schema,
          subject: v.subject
        });

        return {
          subject: v.subject,
          schema: v.schema,
          verified: attestation.data && !attestation.data.revoked,
          data: attestation.data
        };
      } catch (error) {
        return {
          subject: v.subject,
          schema: v.schema,
          verified: false,
          error: error.message
        };
      }
    })
  );

  return results;
}

Parallel Processing

Optimize for high-throughput scenarios:
async function verifyUserPermissions(userAddress: string) {
  // Run all verifications in parallel
  const [kycCheck, reputationCheck, sanctionsCheck] = await Promise.all([
    sdk.fetchAttestation({ schemaUID: 'kyc-basic-v1', subject: userAddress }),
    sdk.fetchAttestation({ schemaUID: 'reputation-v1', subject: userAddress }),
    sdk.fetchAttestation({ schemaUID: 'sanctions-clear-v1', subject: userAddress })
  ]);

  return {
    hasKYC: kycCheck.data && !kycCheck.data.revoked,
    hasReputation: reputationCheck.data && !reputationCheck.data.revoked,
    clearSanctions: sanctionsCheck.data && !sanctionsCheck.data.revoked
  };
}

Error Handling

Graceful Degradation

Handle verification failures appropriately:
async function verifyWithFallback(
  primary: { schema: string; subject: string },
  fallback: { schema: string; subject: string }
) {
  try {
    const primaryResult = await sdk.fetchAttestation({
      schemaUID: primary.schema,
      subject: primary.subject
    });

    if (primaryResult.data && !primaryResult.data.revoked) {
      return { verified: true, level: 'primary', data: primaryResult.data };
    }
  } catch (error) {
    console.warn('Primary verification failed:', error.message);
  }

  try {
    const fallbackResult = await sdk.fetchAttestation({
      schemaUID: fallback.schema,
      subject: fallback.subject
    });

    if (fallbackResult.data && !fallbackResult.data.revoked) {
      return { verified: true, level: 'fallback', data: fallbackResult.data };
    }
  } catch (error) {
    console.warn('Fallback verification failed:', error.message);
  }

  return { verified: false, level: null };
}

Retry Logic

Implement retry strategies for network issues:
async function verifyWithRetry(
  schemaUID: string,
  subject: string,
  maxRetries: number = 3
) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const result = await sdk.fetchAttestation({ schemaUID, subject });
      return result;
    } catch (error) {
      if (attempt === maxRetries) {
        throw new Error(`Verification failed after ${maxRetries} attempts: ${error.message}`);
      }
      
      // Exponential backoff
      await new Promise(resolve => 
        setTimeout(resolve, Math.pow(2, attempt) * 1000)
      );
    }
  }
}

Real-World Integration Examples

Access Control Gate

class AccessController {
  async checkAccess(userAddress: string, resource: string): Promise<boolean> {
    const permissions = await this.getRequiredPermissions(resource);
    
    for (const permission of permissions) {
      const hasPermission = await sdk.fetchAttestation({
        schemaUID: permission.schema,
        subject: userAddress
      });

      if (!hasPermission.data || hasPermission.data.revoked) {
        return false;
      }

      // Check permission level if specified
      if (permission.minLevel) {
        const data = parseAttestationData(hasPermission.data.value);
        if (data.level < permission.minLevel) {
          return false;
        }
      }
    }

    return true;
  }

  private async getRequiredPermissions(resource: string) {
    // Define permissions required for different resources
    const permissionMap = {
      '/admin': [
        { schema: 'admin-role-v1', minLevel: null }
      ],
      '/trading': [
        { schema: 'kyc-basic-v1', minLevel: null },
        { schema: 'trading-license-v1', minLevel: null }
      ],
      '/high-value-trading': [
        { schema: 'kyc-enhanced-v1', minLevel: null },
        { schema: 'accredited-investor-v1', minLevel: null }
      ]
    };

    return permissionMap[resource] || [];
  }
}

Dynamic Pricing Engine

class DynamicPricer {
  async calculatePrice(userAddress: string, basePrice: number): Promise<number> {
    let multiplier = 1.0;

    // Check for premium customer status
    const premiumStatus = await sdk.fetchAttestation({
      schemaUID: 'premium-customer-v1',
      subject: userAddress
    });

    if (premiumStatus.data && !premiumStatus.data.revoked) {
      multiplier *= 0.9; // 10% discount
    }

    // Check reputation score
    const reputation = await sdk.fetchAttestation({
      schemaUID: 'reputation-score-v1',
      subject: userAddress
    });

    if (reputation.data && !reputation.data.revoked) {
      const data = parseAttestationData(reputation.data.value);
      if (data.score > 90) {
        multiplier *= 0.95; // Additional 5% discount for high reputation
      } else if (data.score < 50) {
        multiplier *= 1.1; // 10% surcharge for low reputation
      }
    }

    // Check for loyalty program membership
    const loyalty = await sdk.fetchAttestation({
      schemaUID: 'loyalty-member-v1',
      subject: userAddress
    });

    if (loyalty.data && !loyalty.data.revoked) {
      const data = parseAttestationData(loyalty.data.value);
      const yearsActive = (Date.now() - data.joinDate * 1000) / (365 * 24 * 60 * 60 * 1000);
      
      if (yearsActive > 2) {
        multiplier *= 0.85; // 15% discount for long-term customers
      }
    }

    return Math.round(basePrice * multiplier * 100) / 100;
  }
}

Compliance Checker

class ComplianceChecker {
  async checkCompliance(userAddress: string, jurisdiction: string): Promise<{
    compliant: boolean;
    requirements: string[];
    missing: string[];
  }> {
    const requirements = this.getJurisdictionRequirements(jurisdiction);
    const missing: string[] = [];

    for (const requirement of requirements) {
      const attestation = await sdk.fetchAttestation({
        schemaUID: requirement,
        subject: userAddress
      });

      if (!attestation.data || attestation.data.revoked) {
        missing.push(requirement);
      }
    }

    return {
      compliant: missing.length === 0,
      requirements,
      missing
    };
  }

  private getJurisdictionRequirements(jurisdiction: string): string[] {
    const requirements = {
      'US': ['kyc-enhanced-v1', 'sanctions-screening-v1', 'tax-compliance-v1'],
      'EU': ['kyc-basic-v1', 'gdpr-consent-v1', 'aml-screening-v1'],
      'UK': ['kyc-enhanced-v1', 'fca-approved-v1', 'sanctions-screening-v1']
    };

    return requirements[jurisdiction] || ['kyc-basic-v1'];
  }
}

Monitoring and Analytics

Verification Metrics

Track verification performance and patterns:
interface VerificationMetrics {
  totalVerifications: number;
  successRate: number;
  averageResponseTime: number;
  cacheHitRate: number;
  errorsByType: Record<string, number>;
  schemaUsage: Record<string, number>;
}

class VerificationMonitor {
  private metrics: VerificationMetrics = {
    totalVerifications: 0,
    successRate: 0,
    averageResponseTime: 0,
    cacheHitRate: 0,
    errorsByType: {},
    schemaUsage: {}
  };

  async trackVerification(
    schema: string,
    success: boolean,
    responseTime: number,
    fromCache: boolean = false
  ) {
    this.metrics.totalVerifications++;
    this.metrics.schemaUsage[schema] = (this.metrics.schemaUsage[schema] || 0) + 1;
    
    if (fromCache) {
      this.updateCacheMetrics();
    }

    if (success) {
      this.updateSuccessMetrics(responseTime);
    } else {
      this.updateErrorMetrics(schema);
    }
  }

  getMetrics(): VerificationMetrics {
    return this.metrics;
  }
}

Security Considerations

Input Validation

Always validate inputs before verification:
function validateVerificationInput(schemaUID: string, subject: string): boolean {
  // Validate schema UID format
  if (!schemaUID || typeof schemaUID !== 'string' || schemaUID.length === 0) {
    throw new Error('Invalid schema UID');
  }

  // Validate subject address format
  if (!subject || typeof subject !== 'string') {
    throw new Error('Invalid subject address');
  }

  // Additional blockchain-specific validation
  if (!isValidAddress(subject)) {
    throw new Error('Invalid blockchain address format');
  }

  return true;
}

Rate Limiting

Implement verification rate limiting:
class VerificationRateLimiter {
  private requests = new Map<string, number[]>();
  private maxRequests = 100; // per minute
  private windowMs = 60 * 1000; // 1 minute

  async checkRateLimit(clientId: string): Promise<boolean> {
    const now = Date.now();
    const clientRequests = this.requests.get(clientId) || [];
    
    // Remove old requests outside the window
    const validRequests = clientRequests.filter(time => now - time < this.windowMs);
    
    if (validRequests.length >= this.maxRequests) {
      return false;
    }

    validRequests.push(now);
    this.requests.set(clientId, validRequests);
    return true;
  }
}

Best Practices

  • Cache verification results for frequently checked attestations
  • Use batch verification for multiple checks
  • Implement retry logic with exponential backoff
  • Monitor verification latency and success rates
  • Always validate input parameters
  • Implement rate limiting for public endpoints
  • Use secure communication channels
  • Log verification attempts for audit trails
  • Provide clear feedback on verification status
  • Implement graceful degradation for failed verifications
  • Cache results to avoid repeated network calls
  • Offer alternative verification paths when possible
  • Handle network timeouts and retries
  • Implement fallback verification methods
  • Monitor verification service health
  • Plan for schema evolution and migration

Next Steps