Skip to main content

Overview

The ZKScore Score Calculator is a sophisticated smart contract that computes on-chain reputation scores based on eight distinct categories: DeFi, NFT, Social, Trading, Governance, Gaming, Identity, and Trust. The contract aggregates data from various on-chain sources and applies weighted algorithms to generate comprehensive ZKScores.
The Score Calculator contract is deployed on multiple networks. Always check the latest deployment addresses in the Deployment section before interacting with the contract.

Contract Architecture

Core Components

The Score Calculator consists of several key components:
  1. Category Calculators: Specialized modules for each of the 8 scoring categories
  2. Weight Management: Dynamic weighting system for category importance
  3. Data Aggregation: On-chain data collection and validation
  4. Score Computation: Algorithm for combining category scores
  5. Cache System: Efficient score storage and retrieval

Scoring Categories

1. DeFi Score (Weight: 20%)

Evaluates decentralized finance activity:
  • Liquidity provision
  • Lending/borrowing history
  • Protocol participation
  • Transaction volume
  • Portfolio diversity

2. NFT Score (Weight: 15%)

Measures NFT ecosystem engagement:
  • Collection ownership
  • Trading frequency
  • Rarity score
  • Creator support
  • Community participation

3. Social Score (Weight: 10%)

Assesses social platform activity:
  • Profile completeness
  • Content creation
  • Community engagement
  • Follower quality
  • Reputation signals

4. Trading Score (Weight: 20%)

Evaluates trading performance:
  • Trade volume
  • Success rate
  • Risk management
  • Protocol diversity
  • Market timing

5. Governance Score (Weight: 10%)

Measures governance participation:
  • Proposal voting
  • Delegation activity
  • Forum participation
  • Proposal creation
  • Voting power

6. Gaming Score (Weight: 10%)

Tracks gaming achievements:
  • Games played
  • Achievements earned
  • Leaderboard rankings
  • Tournament participation
  • In-game assets

7. Identity Score (Weight: 10%)

Validates identity strength:
  • Verification level
  • Account age
  • Cross-platform links
  • ENS/ZKS ID ownership
  • Attestations received

8. Trust Score (Weight: 5%)

Evaluates trustworthiness:
  • Attestations given/received
  • Reputation signals
  • Dispute history
  • Community feedback
  • Trust modules passed

Contract Addresses

Mainnet Deployments

// Score Calculator Contract
address: 0x2345678901234567890123456789012345678901

// Proxy Contract
address: 0x3456789012345678901234567890123456789012

Testnet Deployments

// Score Calculator Contract
address: 0x8901234567890123456789012345678901234567

// Proxy Contract
address: 0x9012345678901234567890123456789012345678

Scoring Algorithm

Overall Score Calculation

The total ZKScore is calculated using a weighted average of all category scores:
ZKScore = (DeFi × 0.20) + (NFT × 0.15) + (Social × 0.10) + 
          (Trading × 0.20) + (Governance × 0.10) + (Gaming × 0.10) + 
          (Identity × 0.10) + (Trust × 0.05)

Score Normalization

All category scores are normalized to a 0-1000 scale:
function normalizeScore(uint256 rawScore) internal pure returns (uint256) {
    // Apply logarithmic scaling for fair distribution
    if (rawScore == 0) return 0;
    
    uint256 normalized = (Math.log10(rawScore) * 200);
    return Math.min(normalized, 1000);
}

Score Components

Each category score is composed of multiple sub-metrics:
struct CategoryScore {
    uint256 total;              // Total category score (0-1000)
    uint256[] subScores;        // Individual metric scores
    uint256 weight;             // Category weight (basis points)
    uint256 lastUpdated;        // Timestamp of last update
    bool isActive;              // Category active status
}

Contract Interface

Core Functions

// Score Calculation
function calculateScore(address user) external returns (uint256);
function getScore(address user) external view returns (uint256);
function getScoreBreakdown(address user) external view returns (CategoryScore[8] memory);

// Category Management
function updateCategoryScore(address user, uint8 category, uint256 score) external;
function getCategoryScore(address user, uint8 category) external view returns (uint256);

// Weight Management
function updateCategoryWeight(uint8 category, uint256 newWeight) external;
function getCategoryWeight(uint8 category) external view returns (uint256);

// Cache Management
function refreshScore(address user) external;
function getLastUpdated(address user) external view returns (uint256);

Events

// Score Events
event ScoreCalculated(address indexed user, uint256 totalScore, uint256 timestamp);
event ScoreUpdated(address indexed user, uint256 oldScore, uint256 newScore);
event CategoryScoreUpdated(address indexed user, uint8 indexed category, uint256 score);

// Configuration Events
event CategoryWeightUpdated(uint8 indexed category, uint256 oldWeight, uint256 newWeight);
event CalculatorConfigured(address indexed admin, uint256 timestamp);

Data Sources

On-Chain Data Collection

The Score Calculator collects data from multiple on-chain sources:
// DeFi Data Sources
- Uniswap V2/V3 liquidity pools
- Aave lending positions
- Compound borrowing history
- Curve pool participation
- Balancer liquidity provision

// NFT Data Sources
- OpenSea trading history
- Blur marketplace activity
- NFT collection ownership
- Rarity.tools scores
- NFT staking protocols

// Governance Data Sources
- Snapshot voting records
- Tally governance participation
- Compound governance
- Aave governance
- ENS DAO participation

// Identity Data Sources
- ENS registrations
- ZKS ID ownership
- Proof of Humanity
- BrightID verification
- Worldcoin verification

Score Updates

Automatic Updates

Scores are automatically updated when:
  1. User performs qualifying on-chain action
  2. Scheduled batch update runs (every 24 hours)
  3. User requests manual refresh
  4. Category weight changes occur

Manual Updates

Users can manually trigger score updates:
function refreshScore(address user) external {
    require(msg.sender == user || hasRole(UPDATER_ROLE, msg.sender), "Unauthorized");
    require(block.timestamp >= lastUpdated[user] + MIN_UPDATE_INTERVAL, "Update too soon");
    
    _calculateAndUpdateScore(user);
}

Update Costs

Update TypeGas CostFrequency
Automatic Update~200,000Per qualifying action
Manual Refresh~250,000User-initiated
Batch Update~150,000/userEvery 24 hours
Category Update~50,000Per category change

Gas Optimization

Caching Strategy

The contract implements efficient caching to minimize gas costs:
struct ScoreCache {
    uint256 totalScore;         // Cached total score
    uint256 lastUpdated;        // Last update timestamp
    uint256 updateCount;        // Number of updates
    bool isValid;               // Cache validity flag
}

mapping(address => ScoreCache) private scoreCache;

Batch Operations

For efficiency, the contract supports batch score calculations:
function batchCalculateScores(address[] calldata users) external returns (uint256[] memory) {
    uint256[] memory scores = new uint256[](users.length);
    
    for (uint256 i = 0; i < users.length; i++) {
        scores[i] = calculateScore(users[i]);
    }
    
    return scores;
}

Access Control

Roles

// Role definitions
bytes32 public constant CALCULATOR_ROLE = keccak256("CALCULATOR_ROLE");
bytes32 public constant UPDATER_ROLE = keccak256("UPDATER_ROLE");
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");

// Permission matrix
modifier onlyCalculator() {
    require(hasRole(CALCULATOR_ROLE, msg.sender), "Not authorized calculator");
    _;
}

modifier onlyUpdater() {
    require(hasRole(UPDATER_ROLE, msg.sender), "Not authorized updater");
    _;
}

Permission Matrix

OperationCALCULATOR_ROLEUPDATER_ROLEADMIN_ROLEPublic
Calculate Score
Update Category Score
Update Weights
Refresh Score✅ (own)
View Score

Integration Examples

Basic Score Query

import { ethers } from 'ethers';

// Contract ABI (simplified)
const SCORE_CALCULATOR_ABI = [
  "function getScore(address user) external view returns (uint256)",
  "function getScoreBreakdown(address user) external view returns (tuple(uint256 total, uint256[] subScores, uint256 weight, uint256 lastUpdated, bool isActive)[8])",
  "function calculateScore(address user) external returns (uint256)",
  "event ScoreCalculated(address indexed user, uint256 totalScore, uint256 timestamp)"
];

// Initialize contract
const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
const contract = new ethers.Contract(
  '0x2345678901234567890123456789012345678901',
  SCORE_CALCULATOR_ABI,
  provider
);

// Get user score
async function getUserScore(address) {
  const score = await contract.getScore(address);
  console.log(`User score: ${score.toString()}`);
  return score;
}

// Get score breakdown
async function getScoreBreakdown(address) {
  const breakdown = await contract.getScoreBreakdown(address);
  
  const categories = ['DeFi', 'NFT', 'Social', 'Trading', 'Governance', 'Gaming', 'Identity', 'Trust'];
  
  breakdown.forEach((category, index) => {
    console.log(`${categories[index]}: ${category.total}`);
  });
  
  return breakdown;
}

Score Update

// Refresh user score
async function refreshUserScore(address) {
  const signer = provider.getSigner();
  const contractWithSigner = contract.connect(signer);
  
  const tx = await contractWithSigner.refreshScore(address);
  const receipt = await tx.wait();
  
  // Get new score from event
  const event = receipt.events.find(e => e.event === 'ScoreCalculated');
  const newScore = event.args.totalScore;
  
  console.log(`Score updated: ${newScore.toString()}`);
  return newScore;
}

Security Considerations

Data Validation

All input data is validated before processing:
function updateCategoryScore(address user, uint8 category, uint256 score) 
    external 
    onlyCalculator 
{
    require(user != address(0), "Invalid user address");
    require(category < 8, "Invalid category");
    require(score <= 1000, "Score out of range");
    
    _updateCategoryScore(user, category, score);
}

Reentrancy Protection

All external calls are protected against reentrancy:
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract ScoreCalculator is ReentrancyGuard {
    function calculateScore(address user) 
        external 
        nonReentrant 
        returns (uint256) {
        // Implementation
    }
}

Best Practices

For Developers

  1. Cache Scores: Cache scores locally to minimize gas costs
  2. Batch Queries: Use batch functions when querying multiple users
  3. Monitor Events: Listen for score update events
  4. Validate Input: Always validate user addresses before queries
  5. Handle Errors: Implement comprehensive error handling

For Users

  1. Update Regularly: Keep scores updated for accuracy
  2. Understand Categories: Know how each category contributes
  3. Monitor Changes: Track score changes over time
  4. Optimize Activity: Focus on high-weight categories
  5. Verify Data: Cross-check scores with on-chain data