> ## Documentation Index
> Fetch the complete documentation index at: https://core.anylayer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Ethers.js Integration

> Integrate ZKScore contracts with ethers.js library

## Overview

Complete guide for integrating ZKScore smart contracts using the ethers.js library.

## Installation

```bash theme={null}
npm install ethers
# or
yarn add ethers
```

## Basic Setup

### Provider Configuration

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { ethers } from 'ethers';

  // Provider setup
  const provider = new ethers.providers.JsonRpcProvider(
    'https://eth-mainnet.alchemyapi.io/v2/YOUR_API_KEY'
  );

  // Wallet setup
  const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

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

### Contract Initialization

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Import ABIs
  import IdentitySBTABI from '@zkscore/contracts/abis/IdentitySBT.json';
  import ScoreCalculatorABI from '@zkscore/contracts/abis/ScoreCalculator.json';

  // Initialize contracts
  const identityContract = new ethers.Contract(
    CONTRACTS.identitySBT,
    IdentitySBTABI,
    provider
  );

  const scoreContract = new ethers.Contract(
    CONTRACTS.scoreCalculator,
    ScoreCalculatorABI,
    provider
  );
  ```
</CodeGroup>

## Identity Operations

### Check Identity Status

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function getIdentityInfo(userAddress) {
    try {
      const identity = await identityContract.getIdentity(userAddress);
      const isActivated = await identityContract.isActivated(userAddress);
      
      return {
        exists: identity.exists,
        zksId: identity.zksId,
        displayName: identity.displayName,
        avatarUrl: identity.avatarUrl,
        isActivated: isActivated,
        tokenId: identity.tokenId.toString()
      };
    } catch (error) {
      console.error('Error getting identity:', error);
      return null;
    }
  }
  ```
</CodeGroup>

### Mint Identity

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function mintIdentity(zksId, displayName, avatarUrl) {
    try {
      // Get minting fee
      const mintingFee = await identityContract.mintingFee();
      console.log('Minting fee:', ethers.utils.formatEther(mintingFee), 'ETH');
      
      // Estimate gas
      const gasEstimate = await identityContract.estimateGas.mintIdentity(
        zksId,
        displayName,
        avatarUrl,
        { value: mintingFee }
      );
      
      // Execute transaction
      const tx = await identityContract.mintIdentity(
        zksId,
        displayName,
        avatarUrl,
        { 
          value: mintingFee,
          gasLimit: gasEstimate.mul(120).div(100) // 20% buffer
        }
      );
      
      console.log('Transaction sent:', tx.hash);
      const receipt = await tx.wait();
      console.log('Transaction confirmed:', receipt.transactionHash);
      
      return receipt;
    } catch (error) {
      console.error('Minting failed:', error);
      throw error;
    }
  }
  ```
</CodeGroup>

## Score Operations

### Get User Score

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function getUserScore(userAddress) {
    try {
      const score = await scoreContract.getScore(userAddress);
      const breakdown = await scoreContract.getScoreBreakdown(userAddress);
      
      return {
        total: score.total.toString(),
        breakdown: {
          defi: breakdown.defi.toString(),
          nft: breakdown.nft.toString(),
          social: breakdown.social.toString(),
          trading: breakdown.trading.toString(),
          governance: breakdown.governance.toString(),
          gaming: breakdown.gaming.toString(),
          identity: breakdown.identity.toString(),
          trust: breakdown.trust.toString()
        },
        lastUpdated: new Date(score.lastUpdated.toNumber() * 1000)
      };
    } catch (error) {
      console.error('Error getting score:', error);
      return null;
    }
  }
  ```
</CodeGroup>

### Listen to Score Updates

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Set up event listeners
  function setupScoreListeners() {
    scoreContract.on('ScoreUpdated', (user, oldScore, newScore, category, event) => {
      console.log(`Score updated for ${user}:`);
      console.log(`Old: ${oldScore.toString()}, New: ${newScore.toString()}`);
      console.log(`Category: ${category}`);
      console.log(`Block: ${event.blockNumber}`);
    });
    
    scoreContract.on('ScoreCalculated', (user, totalScore, breakdown, event) => {
      console.log(`Score calculated for ${user}: ${totalScore.toString()}`);
    });
  }

  // Remove listeners when done
  function removeScoreListeners() {
    scoreContract.removeAllListeners('ScoreUpdated');
    scoreContract.removeAllListeners('ScoreCalculated');
  }
  ```
</CodeGroup>

## Achievement Operations

### Get User Achievements

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function getUserAchievements(userAddress) {
    try {
      const achievementCount = await achievementContract.getUserAchievementCount(userAddress);
      const achievements = [];
      
      for (let i = 0; i < achievementCount.toNumber(); i++) {
        const achievement = await achievementContract.getUserAchievement(userAddress, i);
        achievements.push({
          id: achievement.id.toString(),
          name: achievement.name,
          description: achievement.description,
          category: achievement.category,
          rarity: achievement.rarity,
          points: achievement.points.toString(),
          claimedAt: new Date(achievement.claimedAt.toNumber() * 1000)
        });
      }
      
      return achievements;
    } catch (error) {
      console.error('Error getting achievements:', error);
      return [];
    }
  }
  ```
</CodeGroup>

### Claim Achievement

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function claimAchievement(achievementId) {
    try {
      // Check if user can claim
      const canClaim = await achievementContract.canClaimAchievement(
        wallet.address,
        achievementId
      );
      
      if (!canClaim) {
        throw new Error('Cannot claim this achievement');
      }
      
      // Estimate gas
      const gasEstimate = await achievementContract.estimateGas.claimAchievement(
        achievementId
      );
      
      // Execute transaction
      const tx = await achievementContract.claimAchievement(achievementId, {
        gasLimit: gasEstimate.mul(120).div(100)
      });
      
      console.log('Claim transaction sent:', tx.hash);
      const receipt = await tx.wait();
      console.log('Achievement claimed!', receipt.transactionHash);
      
      return receipt;
    } catch (error) {
      console.error('Claim failed:', error);
      throw error;
    }
  }
  ```
</CodeGroup>

## Trust Registry Operations

### Create Attestation

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function createAttestation(recipient, schemaUID, data, expiration, revocable) {
    try {
      // Encode data
      const encodedData = ethers.utils.defaultAbiCoder.encode(
        ['string', 'uint256', 'address'],
        [data.skill, data.level, data.verifiedBy]
      );
      
      // Estimate gas
      const gasEstimate = await trustContract.estimateGas.createAttestation(
        recipient,
        schemaUID,
        encodedData,
        expiration,
        revocable
      );
      
      // Execute transaction
      const tx = await trustContract.createAttestation(
        recipient,
        schemaUID,
        encodedData,
        expiration,
        revocable,
        { gasLimit: gasEstimate.mul(120).div(100) }
      );
      
      console.log('Attestation transaction sent:', tx.hash);
      const receipt = await tx.wait();
      console.log('Attestation created!', receipt.transactionHash);
      
      return receipt;
    } catch (error) {
      console.error('Attestation creation failed:', error);
      throw error;
    }
  }
  ```
</CodeGroup>

### Get Attestations

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function getUserAttestations(userAddress) {
    try {
      const attestationCount = await trustContract.getUserAttestationCount(userAddress);
      const attestations = [];
      
      for (let i = 0; i < attestationCount.toNumber(); i++) {
        const attestation = await trustContract.getUserAttestation(userAddress, i);
        attestations.push({
          uid: attestation.uid,
          attester: attestation.attester,
          recipient: attestation.recipient,
          schema: attestation.schema,
          data: attestation.data,
          expiration: attestation.expiration.toNumber(),
          revocable: attestation.revocable,
          revoked: attestation.revoked
        });
      }
      
      return attestations;
    } catch (error) {
      console.error('Error getting attestations:', error);
      return [];
    }
  }
  ```
</CodeGroup>

## Error Handling

### Comprehensive Error Handling

<CodeGroup>
  ```javascript JavaScript theme={null}
  class ZKScoreError extends Error {
    constructor(message, code, details) {
      super(message);
      this.name = 'ZKScoreError';
      this.code = code;
      this.details = details;
    }
  }

  async function safeContractCall(contractMethod, ...args) {
    try {
      const result = await contractMethod(...args);
      return { success: true, data: result };
    } catch (error) {
      let errorMessage = 'Unknown error';
      let errorCode = 'UNKNOWN_ERROR';
      
      if (error.code === 'INSUFFICIENT_FUNDS') {
        errorMessage = 'Insufficient funds for transaction';
        errorCode = 'INSUFFICIENT_FUNDS';
      } else if (error.code === 'USER_REJECTED') {
        errorMessage = 'User rejected transaction';
        errorCode = 'USER_REJECTED';
      } else if (error.message.includes('Identity already exists')) {
        errorMessage = 'User already has an identity';
        errorCode = 'IDENTITY_EXISTS';
      } else if (error.message.includes('ZKS ID already taken')) {
        errorMessage = 'ZKS ID is already taken';
        errorCode = 'ZKS_ID_TAKEN';
      }
      
      return { 
        success: false, 
        error: new ZKScoreError(errorMessage, errorCode, error) 
      };
    }
  }
  ```
</CodeGroup>

## Best Practices

1. **Always Estimate Gas**: Use gas estimation before transactions
2. **Handle Errors Gracefully**: Implement comprehensive error handling
3. **Use Event Listeners**: 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

## Related Documentation

* [Direct Contract Calls](/contracts/examples/direct-contract-calls)
* [Viem Integration](/contracts/examples/viem-integration)
* [Wagmi Integration](/contracts/examples/wagmi-integration)
