Skip to main content

What are Attestations?

An attestation is a verifiable claim made by a trusted entity (authority) about a subject (user, contract, or organization). Think of attestations as on-chain certificates that prove something about an entity. In the real world, attestations are everywhere:
  • A university diploma attests to your education
  • A driver’s license attests to your driving ability
  • A credit score attests to your financial reliability
  • A vaccination record attests to your health status
AttestProtocol brings this concept to Web3, enabling programmable trust through verifiable on-chain attestations.

Core Components

Every attestation consists of five key components:

Authority

The trusted entity making the claim (KYC provider, DAO, organization)

Subject

The entity the claim is about (wallet address, smart contract, etc.)

Schema

The structure defining what data the attestation contains

Data

The actual claim data (verified: true, score: 85, etc.)

Metadata

Additional info like expiration, creation time, revocation status

Attestation Lifecycle

Attestations follow a predictable lifecycle:

States Explained

The attestation has been issued and recorded on-chain. It’s ready to be used for verification.
The attestation is valid and can be used for verification. This is the normal operating state.
The attestation has passed its expiration date and is no longer valid for verification.
The authority has explicitly revoked the attestation, making it invalid regardless of expiration.
The attestation is kept for historical purposes but is not active.

Types of Attestations

AttestProtocol supports various types of attestations:

Identity Attestations

Verify credentials and identity claims:
// Basic KYC Verification
const kycAttestation = await sdk.attest({
  schemaUID: 'kyc-basic-v1',
  subject: userAddress,
  value: 'verified:true,level:basic,country:US,timestamp:1704067200',
  reference: 'kyc-session-001'
});

// Enhanced Due Diligence
const eddAttestation = await sdk.attest({
  schemaUID: 'kyc-enhanced-v1', 
  subject: userAddress,
  value: 'verified:true,level:enhanced,riskScore:15,pepCheck:true,sanctionsCheck:true,timestamp:1704067200',
  reference: 'edd-session-001'
});

// Professional Certification
const certAttestation = await sdk.attest({
  schemaUID: 'professional-cert-v1',
  subject: developerAddress,
  value: 'title:Certified_Smart_Contract_Auditor,issuer:Web3_Security_Institute,validUntil:1735689600,level:senior',
  reference: 'cert-2024-001'
});

Behavioral Attestations

Document actions, achievements, and behavioral patterns:
// DAO Governance Participation
const participationAttestation = await sdk.attest({
  schemaUID: 'dao-participation-v1',
  subject: memberAddress,
  value: 'proposalsVoted:25,participationRate:85,lastVote:1704067200,reputation:950',
  reference: 'dao-activity-q1-2024'
});

// DeFi Protocol Usage
const defiAttestation = await sdk.attest({
  schemaUID: 'defi-reputation-v1',
  subject: userAddress,
  value: 'totalVolume:500000,protocolsUsed:5,liquidations:0,defaultRate:0,timestamp:1704067200',
  reference: 'defi-analysis-2024'
});

// Gaming Achievement
const achievementAttestation = await sdk.attest({
  schemaUID: 'gaming-achievement-v1',
  subject: playerAddress,
  value: 'gameId:space-raiders,achievementId:master-pilot,rarity:legendary,unlockedAt:1704067200',
  reference: 'achievement-001'
});

Relationship Attestations

Document relationships and affiliations between entities:
// Employment Verification
const employmentAttestation = await sdk.attest({
  schemaUID: 'employment-v1',
  subject: employeeAddress,
  value: 'employer:Acme_Corp,position:Senior_Developer,startDate:1685577600,verified:true,department:Engineering',
  reference: 'emp-verification-001'
});

// DAO Membership
const membershipAttestation = await sdk.attest({
  schemaUID: 'dao-membership-v1',
  subject: memberAddress,
  value: 'dao:CryptoDevs_DAO,memberSince:1672531200,role:contributor,votingPower:1000,active:true',
  reference: 'dao-member-001'
});

// Educational Credentials
const educationAttestation = await sdk.attest({
  schemaUID: 'education-degree-v1',
  subject: graduateAddress,
  value: 'institution:MIT,degree:Master_of_Science,field:Computer_Science,graduationDate:1672531200,gpa:38',
  reference: 'degree-verification-001'
});

Attestation Properties

Immutability

Once created, the core attestation data cannot be changed. This ensures trust and prevents tampering.

Verifiability

Anyone can verify an attestation’s authenticity using cryptographic proofs without revealing sensitive data.

Composability

Attestations can reference other attestations, creating complex trust networks:
// Enhanced KYC that builds on basic KYC
const enhancedKyc = await sdk.attest({
  schemaUID: 'kyc-enhanced-v1',
  subject: userAddress,
  value: 'basicKycRef:att_basic_123,enhancedChecks:sanctions_pep_aml,riskScore:15,additionalDocs:3',
  reference: 'enhanced-kyc-001'
});

// Composite reputation score referencing multiple attestations
const reputationScore = await sdk.attest({
  schemaUID: 'composite-reputation-v1',
  subject: userAddress,
  value: 'kycRef:att_kyc_123,daoRef:att_dao_456,defiRef:att_defi_789,finalScore:925,timestamp:1704067200',
  reference: 'reputation-calc-001'
});

// Cross-chain attestation linking
const crossChainLink = await sdk.attest({
  schemaUID: 'cross-chain-link-v1',
  subject: userAddress,
  value: 'sourceChain:solana,sourceUID:att_sol_123,verified:true,bridgeValidator:bridge_authority_456',
  reference: 'cross-chain-001'
});

Programmability

Smart contracts and applications can automatically verify attestations:
// TypeScript application integration
class SmartContractGate {
  async authorizeTransaction(userAddress: string, amount: number): Promise<boolean> {
    // Basic checks for all transactions
    const basicKyc = await sdk.fetchAttestation({
      schemaUID: 'kyc-basic-v1',
      subject: userAddress
    });

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

    // Enhanced checks for large transactions
    if (amount > 50000) {
      const enhancedKyc = await sdk.fetchAttestation({
        schemaUID: 'kyc-enhanced-v1',
        subject: userAddress
      });

      const sanctionsCheck = await sdk.fetchAttestation({
        schemaUID: 'sanctions-clear-v1',
        subject: userAddress
      });

      return !!(enhancedKyc.data && !enhancedKyc.data.revoked &&
               sanctionsCheck.data && !sanctionsCheck.data.revoked);
    }

    return true;
  }
}

Working with Attestations

Creating Attestations

Using the AttestProtocol SDK to create attestations:
import { AttestSDK } from '@attestprotocol/sdk';

const sdk = await AttestSDK.initializeStellar({
  secretKeyOrCustomSigner: process.env.STELLAR_SECRET_KEY,
  publicKey: process.env.STELLAR_PUBLIC_KEY,
  url: 'https://soroban-testnet.stellar.org'
});

const attestation = await sdk.attest({
  schemaUID: 'user-verification-v1',
  subject: userAddress,
  value: 'verified:true,method:government-id,country:US,timestamp:1704067200',
  reference: 'kyc-session-123'
});

if (attestation.error) {
  console.error('Attestation failed:', attestation.error);
} else {
  console.log('Attestation created:', attestation.data);
}

Fetching Attestations

Retrieve and verify attestations:
// Get specific attestation
const result = await sdk.fetchAttestation({
  schemaUID: 'user-verification-v1',
  subject: userAddress
});

if (result.data && !result.data.revoked) {
  console.log('Valid attestation found');
  console.log('Data:', result.data.value);
  console.log('Authority:', result.data.attester);
  console.log('Timestamp:', new Date(result.data.timestamp * 1000));
} else {
  console.log('No valid attestation found');
}

Revoking Attestations

Authorities can revoke attestations they issued:
// Revoke an attestation
const revocation = await sdk.revokeAttestation({
  schemaUID: 'user-verification-v1',
  subject: userAddress,
  reference: 'kyc-session-123'
});

if (revocation.error) {
  console.error('Revocation failed:', revocation.error);
} else {
  console.log('Attestation successfully revoked');
  
  // Log revocation reason for audit trail
  await auditLog({
    action: 'attestation_revoked',
    attestationUID: revocation.data.attestationUID,
    reason: 'Failed re-verification',
    timestamp: Date.now()
  });
}

Trust Models

AttestProtocol supports different trust models:

Single Authority

One trusted entity issues attestations:
University → Diploma Attestation → Student

Multi-Authority

Multiple entities must agree:
Bank + KYC Provider + Government → High-Trust Attestation → User

Web of Trust

Entities attest to each other:
User A ← Trusts → User B ← Trusts → User C

Delegated Authority

Authorities can delegate attestation power:
Root Authority → Regional Authority → Local Verifier → User

Privacy Considerations

AttestProtocol supports various privacy models:

Public Attestations

Full data is visible on-chain:
{
  verified: true,
  score: 85,
  country: 'US'
}

Private Attestations

Only hashes are stored on-chain:
{
  dataHash: '0xabc123...',
  verified: true  // Only boolean result
}

Zero-Knowledge Attestations

Prove claims without revealing data:
{
  ageOver18: true,  // Without revealing actual age
  hasCleanRecord: true  // Without revealing specifics
}

Best Practices

  • Keep schemas simple and focused
  • Use semantic field names
  • Include version information for evolving schemas
  • Document field meanings clearly
  • Store minimal necessary data
  • Use standard formats (ISO dates, etc.)
  • Consider privacy implications
  • Plan for schema evolution
  • Set appropriate expiration dates
  • Consider renewal processes
  • Balance security with user experience
  • Plan for grace periods
  • Implement proper key management
  • Use multi-sig for critical authorities
  • Plan for authority rotation
  • Monitor for compromised keys

Production Integration Patterns

Access Control System

class AttestationAccessControl {
  private sdk: StellarAttestSDK | SolanaAttestSDK;
  
  constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
    this.sdk = sdk;
  }

  async checkAccess(userAddress: string, requiredPermissions: string[]): Promise<{
    allowed: boolean;
    missingPermissions: string[];
    attestations: any[];
  }> {
    const verifications = await Promise.allSettled(
      requiredPermissions.map(permission => 
        this.sdk.fetchAttestation({
          schemaUID: permission,
          subject: userAddress
        })
      )
    );

    const results = verifications.map((result, index) => ({
      permission: requiredPermissions[index],
      valid: result.status === 'fulfilled' && 
             result.value.data && 
             !result.value.data.revoked,
      attestation: result.status === 'fulfilled' ? result.value.data : null
    }));

    const missingPermissions = results
      .filter(r => !r.valid)
      .map(r => r.permission);

    return {
      allowed: missingPermissions.length === 0,
      missingPermissions,
      attestations: results.filter(r => r.valid).map(r => r.attestation)
    };
  }
}

// Usage
const accessControl = new AttestationAccessControl(sdk);
const access = await accessControl.checkAccess(userAddress, [
  'kyc-basic-v1',
  'sanctions-clear-v1'
]);

if (access.allowed) {
  console.log('Access granted');
} else {
  console.log('Access denied. Missing:', access.missingPermissions);
}

Risk-Based Pricing Engine

class RiskBasedPricer {
  private sdk: StellarAttestSDK | SolanaAttestSDK;
  private baseRate: number;
  
  constructor(sdk: StellarAttestSDK | SolanaAttestSDK, baseRate: number) {
    this.sdk = sdk;
    this.baseRate = baseRate;
  }

  async calculatePremium(userAddress: string): Promise<{
    premium: number;
    riskFactors: any[];
    finalRate: number;
  }> {
    const riskFactors = [];
    let multiplier = 1.0;

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

    if (creditResult.data && !creditResult.data.revoked) {
      const creditData = this.parseAttestationValue(creditResult.data.value);
      const score = parseInt(creditData.score);
      
      if (score > 750) {
        multiplier *= 0.8; // 20% discount
        riskFactors.push({ type: 'credit_score', impact: 'positive', factor: 0.8 });
      } else if (score < 600) {
        multiplier *= 1.5; // 50% increase
        riskFactors.push({ type: 'credit_score', impact: 'negative', factor: 1.5 });
      }
    }

    // Check sanctions screening
    const sanctionsResult = await this.sdk.fetchAttestation({
      schemaUID: 'sanctions-clear-v1',
      subject: userAddress
    });

    if (!sanctionsResult.data || sanctionsResult.data.revoked) {
      multiplier *= 2.0; // 100% increase for unscreened users
      riskFactors.push({ type: 'sanctions_screening', impact: 'negative', factor: 2.0 });
    }

    // Check fraud history
    const fraudResult = await this.sdk.fetchAttestation({
      schemaUID: 'fraud-history-v1',
      subject: userAddress
    });

    if (fraudResult.data && !fraudResult.data.revoked) {
      const fraudData = this.parseAttestationValue(fraudResult.data.value);
      if (fraudData.incidents > 0) {
        multiplier *= 3.0; // 200% increase
        riskFactors.push({ type: 'fraud_history', impact: 'negative', factor: 3.0 });
      }
    }

    const finalRate = this.baseRate * multiplier;

    return {
      premium: multiplier,
      riskFactors,
      finalRate: Math.round(finalRate * 100) / 100
    };
  }

  private parseAttestationValue(value: string): Record<string, string> {
    const pairs = value.split(',');
    const result: Record<string, string> = {};
    
    pairs.forEach(pair => {
      const [key, val] = pair.split(':');
      result[key] = val;
    });
    
    return result;
  }
}

Compliance Verification System

class ComplianceVerifier {
  private sdk: StellarAttestSDK | SolanaAttestSDK;
  
  constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
    this.sdk = sdk;
  }

  async verifyCompliance(
    userAddress: string, 
    jurisdiction: string, 
    transactionAmount: number
  ): Promise<{
    compliant: boolean;
    requirements: ComplianceRequirement[];
    recommendations: string[];
  }> {
    const requirements = this.getComplianceRequirements(jurisdiction, transactionAmount);
    const verificationResults = [];
    const recommendations = [];

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

      const isValid = result.data && 
                     !result.data.revoked && 
                     this.checkExpiration(result.data, requirement.maxAge);

      verificationResults.push({
        ...requirement,
        satisfied: isValid,
        attestation: result.data
      });

      if (!isValid) {
        recommendations.push(
          `Complete ${requirement.name} verification to meet ${jurisdiction} requirements`
        );
      }
    }

    return {
      compliant: verificationResults.every(r => r.satisfied),
      requirements: verificationResults,
      recommendations
    };
  }

  private getComplianceRequirements(
    jurisdiction: string, 
    amount: number
  ): ComplianceRequirement[] {
    const baseRequirements = {
      'US': [
        { name: 'Basic KYC', schemaUID: 'kyc-basic-v1', maxAge: 365 },
        { name: 'Sanctions Screening', schemaUID: 'sanctions-clear-v1', maxAge: 30 }
      ],
      'EU': [
        { name: 'Basic KYC', schemaUID: 'kyc-basic-v1', maxAge: 365 },
        { name: 'GDPR Compliance', schemaUID: 'gdpr-consent-v1', maxAge: 365 }
      ]
    };

    let requirements = baseRequirements[jurisdiction] || baseRequirements['US'];

    // Enhanced requirements for large transactions
    if (amount > 50000) {
      requirements.push({
        name: 'Enhanced Due Diligence',
        schemaUID: 'kyc-enhanced-v1',
        maxAge: 180
      });
    }

    if (amount > 100000) {
      requirements.push({
        name: 'Source of Funds',
        schemaUID: 'source-of-funds-v1',
        maxAge: 90
      });
    }

    return requirements;
  }

  private checkExpiration(attestation: any, maxAgeDays: number): boolean {
    const ageInDays = (Date.now() / 1000 - attestation.timestamp) / (24 * 60 * 60);
    return ageInDays <= maxAgeDays;
  }
}

interface ComplianceRequirement {
  name: string;
  schemaUID: string;
  maxAge: number; // days
  satisfied?: boolean;
  attestation?: any;
}

Next Steps