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:Copy
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.Copy
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.Copy
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.Copy
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
Copy
// 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
Copy
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
Copy
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
- Gas Efficiency: Optimize for low gas consumption
- View Functions: Keep evaluateTrust as view function
- Parameterization: Make modules configurable
- Documentation: Document evaluation logic clearly
- Testing: Test thoroughly before deployment
Module Usage
- Understand Logic: Know how each module evaluates
- Appropriate Weighting: Weight modules based on importance
- Combine Strategically: Use complementary modules
- Monitor Performance: Track evaluation gas costs
- Update Regularly: Review and update module configurations
Related Documentation
- Contract Overview - Contract architecture
- Functions Reference - Function documentation
- Events Reference - Event documentation
- Integration Guide - Integration examples