Skip to main content

Overview

This document provides a comprehensive reference for all functions available in the ZKScore Achievement Registry contract. Each function includes detailed parameter descriptions, return values, gas estimates, and usage examples.
All functions that modify state require a transaction and will consume gas. View functions are free to call and return data immediately.

Achievement Management Functions

createAchievement

Create a new achievement in the registry.
function createAchievement(
    string memory name,
    string memory description,
    string memory imageURI,
    uint8 category,
    Rarity rarity,
    uint256 points,
    uint256 scoreBoost,
    RequirementType requirementType,
    bytes memory requirementData
) external returns (uint256);
Parameters:
  • name (string): Achievement name
  • description (string): Achievement description
  • imageURI (string): URI for achievement image/badge
  • category (uint8): Category index (0-7)
  • rarity (Rarity): Rarity level (0-4)
  • points (uint256): Points awarded upon claiming
  • scoreBoost (uint256): Score boost percentage (basis points)
  • requirementType (RequirementType): Type of requirement verification
  • requirementData (bytes): Encoded requirement data
Returns:
  • uint256: The newly created achievement ID
Gas Estimate: ~200,000 gas Requirements:
  • Caller must have CREATOR_ROLE
  • Name cannot be empty
  • Points must be > 0
  • Category must be valid (0-7)
Events Emitted:
  • AchievementCreated(uint256 indexed achievementId, string name, uint8 category, Rarity rarity)
Example Usage:
const { ethers } = require('ethers');

async function createAchievement() {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  const signer = provider.getSigner();
  
  const contract = new ethers.Contract(
    '0x3456789012345678901234567890123456789012',
    ACHIEVEMENT_REGISTRY_ABI,
    signer
  );
  
  // Encode requirement data for score threshold
  const requirementData = ethers.utils.defaultAbiCoder.encode(
    ['uint256'],
    [500] // Minimum score of 500
  );
  
  const tx = await contract.createAchievement(
    'DeFi Explorer',
    'Use 5 different DeFi protocols',
    'ipfs://QmXyz.../defi-explorer.png',
    0, // DeFi category
    1, // UNCOMMON rarity
    100, // 100 points
    200, // 2% score boost (200 basis points)
    1, // SCORE_THRESHOLD requirement type
    requirementData
  );
  
  const receipt = await tx.wait();
  const event = receipt.events.find(e => e.event === 'AchievementCreated');
  const achievementId = event.args.achievementId;
  
  console.log(`Achievement created with ID: ${achievementId.toString()}`);
  return achievementId;
}

updateAchievement

Update an existing achievement’s configuration.
function updateAchievement(
    uint256 achievementId,
    bytes memory updateData
) external;
Parameters:
  • achievementId (uint256): ID of achievement to update
  • updateData (bytes): Encoded update data
Returns: None Gas Estimate: ~80,000 gas Requirements:
  • Caller must have CREATOR_ROLE
  • Achievement must exist
  • Achievement must be active
Events Emitted:
  • AchievementUpdated(uint256 indexed achievementId, bytes updateData)

deactivateAchievement

Deactivate an achievement (prevent new claims).
function deactivateAchievement(uint256 achievementId) external;
Parameters:
  • achievementId (uint256): ID of achievement to deactivate
Returns: None Gas Estimate: ~30,000 gas Requirements:
  • Caller must have ADMIN_ROLE
  • Achievement must exist
Events Emitted:
  • AchievementDeactivated(uint256 indexed achievementId, uint256 timestamp)

Claiming Functions

claimAchievement

Claim an achievement and receive rewards.
function claimAchievement(
    uint256 achievementId,
    bytes memory proof
) external;
Parameters:
  • achievementId (uint256): ID of achievement to claim
  • proof (bytes): Verification proof (if required)
Returns: None Gas Estimate: ~180,000 gas (includes badge minting) Requirements:
  • Achievement must be active
  • User must not have already claimed
  • User must meet requirements
Events Emitted:
  • AchievementClaimed(address indexed user, uint256 indexed achievementId, uint256 timestamp)
  • BadgeMinted(address indexed user, uint256 indexed achievementId, uint256 tokenId)
Example Usage:
async function claimAchievement(achievementId) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  const signer = provider.getSigner();
  
  const contract = new ethers.Contract(
    '0x3456789012345678901234567890123456789012',
    ACHIEVEMENT_REGISTRY_ABI,
    signer
  );
  
  // Generate proof (if needed)
  const proof = '0x'; // Empty proof for automatic verification
  
  const tx = await contract.claimAchievement(achievementId, proof);
  const receipt = await tx.wait();
  
  // Get claim event
  const claimEvent = receipt.events.find(e => e.event === 'AchievementClaimed');
  const badgeEvent = receipt.events.find(e => e.event === 'BadgeMinted');
  
  console.log('Achievement claimed!');
  console.log('Timestamp:', claimEvent.args.timestamp.toString());
  console.log('Badge Token ID:', badgeEvent.args.tokenId.toString());
  
  return receipt;
}

batchClaimAchievements

Claim multiple achievements in a single transaction.
function batchClaimAchievements(
    uint256[] calldata achievementIds,
    bytes[] calldata proofs
) external returns (uint256[] memory);
Parameters:
  • achievementIds (uint256[]): Array of achievement IDs to claim
  • proofs (bytes[]): Array of corresponding proofs
Returns:
  • uint256[]: Array of minted badge token IDs
Gas Estimate: ~150,000 + (180,000 × number of achievements) Requirements:
  • Arrays must have equal length
  • Each achievement must be claimable

Query Functions

getAchievement

Get detailed information about an achievement.
function getAchievement(uint256 achievementId) 
    external 
    view 
    returns (Achievement memory);
Parameters:
  • achievementId (uint256): ID of achievement to query
Returns:
  • Achievement: Achievement struct with all details
Gas Estimate: ~5,000 gas (view function) Example Usage:
async function getAchievement(achievementId) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  
  const contract = new ethers.Contract(
    '0x3456789012345678901234567890123456789012',
    ACHIEVEMENT_REGISTRY_ABI,
    provider
  );
  
  const achievement = await contract.getAchievement(achievementId);
  
  console.log('Achievement:', {
    id: achievement.id.toString(),
    name: achievement.name,
    description: achievement.description,
    category: achievement.category,
    rarity: achievement.rarity,
    points: achievement.points.toString(),
    totalClaimed: achievement.totalClaimed.toString(),
    isActive: achievement.isActive
  });
  
  return achievement;
}

getUserAchievements

Get all achievements earned by a user.
function getUserAchievements(address user) 
    external 
    view 
    returns (uint256[] memory);
Parameters:
  • user (address): User address to query
Returns:
  • uint256[]: Array of achievement IDs
Gas Estimate: ~3,000 + (1,000 × number of achievements) (view function)

getProgress

Get user’s progress for a specific achievement.
function getProgress(address user, uint256 achievementId) 
    external 
    view 
    returns (Progress memory);
Parameters:
  • user (address): User address
  • achievementId (uint256): Achievement ID
Returns:
  • Progress: Progress struct with current/required/percentage/canClaim
Gas Estimate: ~4,000 gas (view function) Example Usage:
async function getProgress(userAddress, achievementId) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  
  const contract = new ethers.Contract(
    '0x3456789012345678901234567890123456789012',
    ACHIEVEMENT_REGISTRY_ABI,
    provider
  );
  
  const progress = await contract.getProgress(userAddress, achievementId);
  
  console.log('Progress:', {
    current: progress.current.toString(),
    required: progress.required.toString(),
    percentage: progress.percentage.toString(),
    lastUpdated: new Date(progress.lastUpdated.toNumber() * 1000).toISOString(),
    canClaim: progress.canClaim
  });
  
  return progress;
}

getAchievementsByCategory

Get all achievements in a specific category.
function getAchievementsByCategory(uint8 category) 
    external 
    view 
    returns (uint256[] memory);
Parameters:
  • category (uint8): Category index (0-7)
Returns:
  • uint256[]: Array of achievement IDs
Gas Estimate: ~3,000 + (500 × number of achievements) (view function)

getAchievementsByRarity

Get all achievements of a specific rarity.
function getAchievementsByRarity(Rarity rarity) 
    external 
    view 
    returns (uint256[] memory);
Parameters:
  • rarity (Rarity): Rarity level (0-4)
Returns:
  • uint256[]: Array of achievement IDs
Gas Estimate: ~3,000 + (500 × number of achievements) (view function)

Progress Management Functions

updateProgress

Update progress for a user (verifier only).
function updateProgress(
    address user,
    uint256 achievementId,
    uint256 progressValue
) external;
Parameters:
  • user (address): User address
  • achievementId (uint256): Achievement ID
  • progressValue (uint256): New progress value
Returns: None Gas Estimate: ~50,000 gas Requirements:
  • Caller must have VERIFIER_ROLE
  • Achievement must exist
  • User must not have claimed yet
Events Emitted:
  • ProgressUpdated(address indexed user, uint256 indexed achievementId, uint256 progress)

batchUpdateProgress

Update progress for multiple users.
function batchUpdateProgress(
    address[] calldata users,
    uint256[] calldata achievementIds,
    uint256[] calldata progressValues
) external;
Parameters:
  • users (address[]): Array of user addresses
  • achievementIds (uint256[]): Array of achievement IDs
  • progressValues (uint256[]): Array of progress values
Returns: None Gas Estimate: ~40,000 + (50,000 × number of updates) Requirements:
  • All arrays must have equal length
  • Caller must have VERIFIER_ROLE

Badge Functions

getBadge

Get badge information for a claimed achievement.
function getBadge(uint256 tokenId) 
    external 
    view 
    returns (Badge memory);
Parameters:
  • tokenId (uint256): Badge token ID
Returns:
  • Badge: Badge struct with achievement ID, owner, claim timestamp
Gas Estimate: ~3,000 gas (view function)

getUserBadges

Get all badges owned by a user.
function getUserBadges(address user) 
    external 
    view 
    returns (uint256[] memory);
Parameters:
  • user (address): User address
Returns:
  • uint256[]: Array of badge token IDs
Gas Estimate: ~3,000 + (500 × number of badges) (view function)

Verification Functions

canClaim

Check if a user can claim an achievement.
function canClaim(address user, uint256 achievementId) 
    external 
    view 
    returns (bool);
Parameters:
  • user (address): User address
  • achievementId (uint256): Achievement ID
Returns:
  • bool: True if user can claim, false otherwise
Gas Estimate: ~5,000 gas (view function)

hasClaimed

Check if a user has already claimed an achievement.
function hasClaimed(address user, uint256 achievementId) 
    external 
    view 
    returns (bool);
Parameters:
  • user (address): User address
  • achievementId (uint256): Achievement ID
Returns:
  • bool: True if already claimed, false otherwise
Gas Estimate: ~2,000 gas (view function)

Error Handling

Common Errors

ErrorDescriptionSolution
"Achievement not active"Achievement is deactivatedCheck achievement status
"Already claimed"User already claimedCheck hasClaimed() first
"Requirements not met"User doesn’t meet requirementsCheck progress/requirements
"Invalid category"Category index > 7Use valid category (0-7)
"Invalid rarity"Rarity index > 4Use valid rarity (0-4)
"Achievement not found"Invalid achievement IDVerify achievement ID

Error Handling Examples

async function safeClaimAchievement(achievementId) {
  try {
    // Check if can claim
    const canClaim = await contract.canClaim(userAddress, achievementId);
    if (!canClaim) {
      throw new Error('Cannot claim achievement yet');
    }
    
    // Check if already claimed
    const hasClaimed = await contract.hasClaimed(userAddress, achievementId);
    if (hasClaimed) {
      throw new Error('Achievement already claimed');
    }
    
    // Claim achievement
    const tx = await contract.claimAchievement(achievementId, '0x');
    const receipt = await tx.wait();
    
    return receipt;
  } catch (error) {
    if (error.message.includes('Requirements not met')) {
      console.error('You do not meet the requirements for this achievement');
    } else if (error.message.includes('Achievement not active')) {
      console.error('This achievement is no longer available');
    } else {
      console.error('Claim failed:', error.message);
    }
    throw error;
  }
}

Gas Optimization Tips

Batch Operations

// Instead of claiming one by one
for (const id of achievementIds) {
  await contract.claimAchievement(id, '0x');
}

// Use batch claim
await contract.batchClaimAchievements(achievementIds, proofs);

Query Optimization

// Query all achievements at once
const achievements = await contract.batchGetAchievements(achievementIds);

// Instead of individual queries
for (const id of achievementIds) {
  const achievement = await contract.getAchievement(id);
}