Skip to main content

Overview

Trust modules are pluggable smart contracts that implement custom trust evaluation logic. They enable flexible trust scoring based on different criteria, attestation patterns, and reputation signals.
Trust modules enable composable trust evaluation. You can combine multiple modules to create sophisticated trust scoring systems.

Module Interface

ITrustModule Interface

All trust modules must implement this interface:
interface ITrustModule {
    /**
     * @dev Evaluate trust score for a subject
     * @param subject Address to evaluate
     * @param context Module-specific context data
     * @return Trust score (0-1000)
     */
    function evaluateTrust(
        address subject,
        bytes calldata context
    ) external view returns (uint256);
    
    /**
     * @dev Get required attestation schemas
     * @return Array of schema UIDs required by this module
     */
    function getRequiredSchemas() external view returns (bytes32[] memory);
    
    /**
     * @dev Get module name
     * @return Module name
     */
    function getName() external view returns (string memory);
    
    /**
     * @dev Get module version
     * @return Module version
     */
    function getVersion() external view returns (string memory);
}

Built-in Modules

Attestation Count Module

Evaluates trust based on total number of attestations.
contract AttestationCountModule is ITrustModule {
    ITrustRegistry public trustRegistry;
    
    constructor(address _trustRegistry) {
        trustRegistry = ITrustRegistry(_trustRegistry);
    }
    
    function evaluateTrust(address subject, bytes calldata context) 
        external 
        view 
        returns (uint256) {
        // Get attestation count
        bytes32[] memory uids = trustRegistry.getReceivedAttestationUIDs(
            subject,
            bytes32(0), // All schemas
            0,
            1000,
            false
        );
        
        uint256 activeCount = 0;
        for (uint256 i = 0; i < uids.length; i++) {
            if (trustRegistry.isAttestationValid(uids[i])) {
                activeCount++;
            }
        }
        
        // Score: 100 points per attestation, max 1000
        return min(activeCount * 100, 1000);
    }
    
    function getRequiredSchemas() external pure returns (bytes32[] memory) {
        return new bytes32[](0); // No specific schema required
    }
    
    function getName() external pure returns (string memory) {
        return "Attestation Count Module";
    }
    
    function getVersion() external pure returns (string memory) {
        return "1.0.0";
    }
}

Attester Reputation Module

Weighs attestations by attester reputation.
contract AttesterReputationModule is ITrustModule {
    ITrustRegistry public trustRegistry;
    mapping(address => uint256) public attesterReputation;
    
    function evaluateTrust(address subject, bytes calldata context) 
        external 
        view 
        returns (uint256) {
        bytes32[] memory uids = trustRegistry.getReceivedAttestationUIDs(
            subject,
            bytes32(0),
            0,
            1000,
            false
        );
        
        uint256 weightedScore = 0;
        uint256 totalWeight = 0;
        
        for (uint256 i = 0; i < uids.length; i++) {
            Attestation memory att = trustRegistry.getAttestation(uids[i]);
            
            if (!att.revoked) {
                uint256 weight = attesterReputation[att.attester];
                if (weight == 0) weight = 100; // Default weight
                
                weightedScore += weight;
                totalWeight += weight;
            }
        }
        
        if (totalWeight == 0) return 0;
        
        return min((weightedScore * 1000) / totalWeight, 1000);
    }
    
    function getName() external pure returns (string memory) {
        return "Attester Reputation Module";
    }
}

Schema-Specific Module

Evaluates based on specific attestation schemas.
contract SchemaSpecificModule is ITrustModule {
    ITrustRegistry public trustRegistry;
    bytes32 public requiredSchema;
    uint256 public scorePerAttestation;
    
    constructor(address _trustRegistry, bytes32 _schema, uint256 _scorePerAttestation) {
        trustRegistry = ITrustRegistry(_trustRegistry);
        requiredSchema = _schema;
        scorePerAttestation = _scorePerAttestation;
    }
    
    function evaluateTrust(address subject, bytes calldata context) 
        external 
        view 
        returns (uint256) {
        bytes32[] memory uids = trustRegistry.getReceivedAttestationUIDs(
            subject,
            requiredSchema,
            0,
            1000,
            false
        );
        
        uint256 count = 0;
        for (uint256 i = 0; i < uids.length; i++) {
            if (trustRegistry.isAttestationValid(uids[i])) {
                count++;
            }
        }
        
        return min(count * scorePerAttestation, 1000);
    }
    
    function getRequiredSchemas() external view returns (bytes32[] memory) {
        bytes32[] memory schemas = new bytes32[](1);
        schemas[0] = requiredSchema;
        return schemas;
    }
    
    function getName() external pure returns (string memory) {
        return "Schema-Specific Module";
    }
}

Custom Module Development

Creating a Custom Module

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "./ITrustModule.sol";
import "./ITrustRegistry.sol";

contract CustomTrustModule is ITrustModule {
    ITrustRegistry public trustRegistry;
    
    // Custom parameters
    uint256 public minAttestations;
    uint256 public maxAge;
    
    constructor(
        address _trustRegistry,
        uint256 _minAttestations,
        uint256 _maxAge
    ) {
        trustRegistry = ITrustRegistry(_trustRegistry);
        minAttestations = _minAttestations;
        maxAge = _maxAge;
    }
    
    function evaluateTrust(
        address subject,
        bytes calldata context
    ) external view returns (uint256) {
        // Get attestations
        bytes32[] memory uids = trustRegistry.getReceivedAttestationUIDs(
            subject,
            bytes32(0),
            0,
            1000,
            false
        );
        
        uint256 validCount = 0;
        uint256 totalWeight = 0;
        
        for (uint256 i = 0; i < uids.length; i++) {
            Attestation memory att = trustRegistry.getAttestation(uids[i]);
            
            // Check validity
            if (att.revoked) continue;
            
            // Check age
            uint256 age = block.timestamp - att.time;
            if (age > maxAge) continue;
            
            validCount++;
            
            // Apply time decay
            uint256 decayFactor = calculateDecay(age);
            totalWeight += decayFactor;
        }
        
        // Require minimum attestations
        if (validCount < minAttestations) {
            return 0;
        }
        
        // Calculate final score
        uint256 baseScore = min(validCount * 100, 500);
        uint256 weightedScore = min((totalWeight / validCount) * 50, 500);
        
        return min(baseScore + weightedScore, 1000);
    }
    
    function calculateDecay(uint256 age) internal view returns (uint256) {
        // Linear decay over maxAge period
        if (age >= maxAge) return 0;
        
        uint256 decay = ((maxAge - age) * 100) / maxAge;
        return decay;
    }
    
    function getRequiredSchemas() external pure returns (bytes32[] memory) {
        return new bytes32[](0);
    }
    
    function getName() external pure returns (string memory) {
        return "Custom Trust Module";
    }
    
    function getVersion() external pure returns (string memory) {
        return "1.0.0";
    }
}

Deploying Custom Module

async function deployCustomModule() {
  const CustomTrustModule = await ethers.getContractFactory('CustomTrustModule');
  
  const module = await CustomTrustModule.deploy(
    TRUST_REGISTRY_ADDRESS,
    5, // Minimum 5 attestations
    365 * 24 * 60 * 60 // Max age: 1 year
  );
  
  await module.deployed();
  
  console.log('Custom module deployed:', module.address);
  
  // Register with trust registry
  const tx = await trustRegistry.registerTrustModule(
    module.address,
    'Custom Trust Module'
  );
  
  await tx.wait();
  
  console.log('Module registered with trust registry');
  
  return module.address;
}

Module Composition

Combining Multiple Modules

class CompositeModuleEvaluator {
  constructor(trustRegistry, modules) {
    this.trustRegistry = trustRegistry;
    this.modules = modules;
  }
  
  async evaluateTrust(subject) {
    const scores = await Promise.all(
      this.modules.map(async module => {
        const score = await module.contract.evaluateTrust(
          subject,
          module.context || '0x'
        );
        
        return {
          name: await module.contract.getName(),
          score: score.toNumber(),
          weight: module.weight || 1
        };
      })
    );
    
    // Calculate weighted average
    const totalWeight = scores.reduce((sum, s) => sum + s.weight, 0);
    const weightedSum = scores.reduce((sum, s) => sum + (s.score * s.weight), 0);
    
    const finalScore = Math.round(weightedSum / totalWeight);
    
    return {
      finalScore,
      breakdown: scores,
      totalWeight
    };
  }
}

// Usage
const evaluator = new CompositeModuleEvaluator(trustRegistry, [
  { contract: attestationCountModule, weight: 2 },
  { contract: attesterReputationModule, weight: 3 },
  { contract: schemaSpecificModule, weight: 1 }
]);

const result = await evaluator.evaluateTrust('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
console.log('Composite Trust Score:', result);

Best Practices

Module Development

  1. Gas Efficiency: Optimize for low gas consumption
  2. View Functions: Keep evaluateTrust as view function
  3. Parameterization: Make modules configurable
  4. Documentation: Document evaluation logic clearly
  5. Testing: Test thoroughly before deployment

Module Usage

  1. Understand Logic: Know how each module evaluates
  2. Appropriate Weighting: Weight modules based on importance
  3. Combine Strategically: Use complementary modules
  4. Monitor Performance: Track evaluation gas costs
  5. Update Regularly: Review and update module configurations