Skip to main content

Overview

Learn how to interact with ZKScore smart contracts directly using Web3 libraries like ethers.js, web3.js, or viem.

Prerequisites

  • Web3 Library: ethers.js, web3.js, or viem
  • Contract Addresses: ZKScore contract addresses
  • ABI Files: Contract Application Binary Interfaces
  • RPC Provider: Ethereum RPC endpoint

Basic Setup

Import Libraries

// ethers.js
import { ethers } from 'ethers';

// web3.js
import Web3 from 'web3';

// viem
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';

Contract Configuration

// Contract addresses
const CONTRACTS = {
  identitySBT: '0x1234567890123456789012345678901234567890',
  scoreCalculator: '0x2345678901234567890123456789012345678901',
  achievementRegistry: '0x3456789012345678901234567890123456789012',
  trustRegistry: '0x4567890123456789012345678901234567890123'
};

// ABI imports
import IdentitySBTABI from '@zkscore/contracts/abis/IdentitySBT.json';
import ScoreCalculatorABI from '@zkscore/contracts/abis/ScoreCalculator.json';

Identity SBT Interactions

Check Identity Status

// ethers.js
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const identityContract = new ethers.Contract(
  CONTRACTS.identitySBT,
  IdentitySBTABI,
  provider
);

async function checkIdentity(userAddress) {
  const identity = await identityContract.getIdentity(userAddress);
  console.log('Identity:', identity);
  
  const isActivated = await identityContract.isActivated(userAddress);
  console.log('Is activated:', isActivated);
}

Mint Identity

// ethers.js with wallet
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
const identityContract = new ethers.Contract(
  CONTRACTS.identitySBT,
  IdentitySBTABI,
  wallet
);

async function mintIdentity(zksId, displayName, avatarUrl) {
  const mintingFee = await identityContract.mintingFee();
  
  const tx = await identityContract.mintIdentity(
    zksId,
    displayName,
    avatarUrl,
    { value: mintingFee }
  );
  
  await tx.wait();
  console.log('Identity minted!', tx.hash);
}

Score Calculator Interactions

Get User Score

// ethers.js
const scoreContract = new ethers.Contract(
  CONTRACTS.scoreCalculator,
  ScoreCalculatorABI,
  provider
);

async function getUserScore(userAddress) {
  const score = await scoreContract.getScore(userAddress);
  console.log('Total score:', score.total.toString());
  
  const breakdown = await scoreContract.getScoreBreakdown(userAddress);
  console.log('Score breakdown:', breakdown);
}

Listen to Score Updates

// Listen to score update events
scoreContract.on('ScoreUpdated', (user, oldScore, newScore, category, event) => {
  console.log(`Score updated for ${user}:`);
  console.log(`Old score: ${oldScore.toString()}`);
  console.log(`New score: ${newScore.toString()}`);
  console.log(`Category: ${category}`);
});

Achievement Registry Interactions

Get User Achievements

// Get user achievements
async function getUserAchievements(userAddress) {
  const achievementCount = await achievementContract.getUserAchievementCount(userAddress);
  console.log('Achievement count:', achievementCount.toString());
  
  const achievements = [];
  for (let i = 0; i < achievementCount; i++) {
    const achievement = await achievementContract.getUserAchievement(userAddress, i);
    achievements.push(achievement);
  }
  
  return achievements;
}

Claim Achievement

// Claim achievement with wallet
const achievementContract = new ethers.Contract(
  CONTRACTS.achievementRegistry,
  AchievementRegistryABI,
  wallet
);

async function claimAchievement(achievementId) {
  const tx = await achievementContract.claimAchievement(achievementId);
  await tx.wait();
  console.log('Achievement claimed!', tx.hash);
}

Trust Registry Interactions

Create Attestation

// Create attestation
async function createAttestation(recipient, schemaUID, data, expiration, revocable) {
  const tx = await trustContract.createAttestation(
    recipient,
    schemaUID,
    data,
    expiration,
    revocable
  );
  
  await tx.wait();
  console.log('Attestation created!', tx.hash);
}

Get Attestations

// Get user attestations
async function getUserAttestations(userAddress) {
  const attestationCount = await trustContract.getUserAttestationCount(userAddress);
  console.log('Attestation count:', attestationCount.toString());
  
  const attestations = [];
  for (let i = 0; i < attestationCount; i++) {
    const attestation = await trustContract.getUserAttestation(userAddress, i);
    attestations.push(attestation);
  }
  
  return attestations;
}

Error Handling

Common Error Patterns

// Comprehensive error handling
async function safeContractCall(contractMethod, ...args) {
  try {
    const result = await contractMethod(...args);
    return { success: true, data: result };
  } catch (error) {
    console.error('Contract call failed:', error);
    
    if (error.code === 'INSUFFICIENT_FUNDS') {
      return { success: false, error: 'Insufficient funds for transaction' };
    } else if (error.code === 'USER_REJECTED') {
      return { success: false, error: 'User rejected transaction' };
    } else {
      return { success: false, error: error.message };
    }
  }
}

Gas Optimization

Gas Estimation

// Estimate gas before transaction
async function estimateGas(contractMethod, ...args) {
  try {
    const gasEstimate = await contractMethod.estimateGas(...args);
    console.log('Gas estimate:', gasEstimate.toString());
    
    // Add 20% buffer
    const gasLimit = gasEstimate.mul(120).div(100);
    return gasLimit;
  } catch (error) {
    console.error('Gas estimation failed:', error);
    return null;
  }
}

Batch Transactions

// Batch multiple contract calls
async function batchContractCalls(calls) {
  const results = [];
  
  for (const call of calls) {
    try {
      const result = await call.contractMethod(...call.args);
      results.push({ success: true, data: result });
    } catch (error) {
      results.push({ success: false, error: error.message });
    }
  }
  
  return results;
}

Best Practices

  1. Always Estimate Gas: Estimate gas before transactions
  2. Handle Errors Gracefully: Implement comprehensive error handling
  3. Use Events: Listen to contract events for real-time updates
  4. Batch Operations: Combine multiple calls when possible
  5. Monitor Gas Prices: Use appropriate gas prices for network conditions