> ## 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.

# Creating Custom Achievements

> Guide to creating and deploying custom achievements

## Overview

This guide explains how to create custom achievements tailored to your application's needs. Custom achievements enable you to reward users for specific behaviors, milestones, or accomplishments unique to your platform.

<Tip>
  Custom achievements should align with your platform's goals and provide meaningful recognition for user accomplishments.
</Tip>

## Achievement Design

### Planning Your Achievement

Before creating an achievement, consider:

1. **Purpose**: What behavior are you rewarding?
2. **Requirements**: What must users do to earn it?
3. **Rarity**: How difficult should it be?
4. **Rewards**: What points/boost should it grant?
5. **Verification**: How will you verify completion?

### Achievement Categories

Choose the most appropriate category:

* **DeFi**: Financial protocol interactions
* **NFT**: NFT-related activities
* **Social**: Community engagement
* **Trading**: Trading performance
* **Governance**: DAO participation
* **Gaming**: Gaming achievements
* **Identity**: Identity verification
* **Trust**: Trust-building activities

### Rarity Guidelines

| Rarity    | Difficulty     | User % | Points   | Boost |
| --------- | -------------- | ------ | -------- | ----- |
| Common    | Easy           | 60%    | 10-50    | +1%   |
| Uncommon  | Moderate       | 30%    | 50-100   | +2%   |
| Rare      | Challenging    | 8%     | 100-250  | +5%   |
| Epic      | Very Hard      | 1.5%   | 250-500  | +10%  |
| Legendary | Extremely Rare | 0.5%   | 500-1000 | +20%  |

## Requirement Types

### 1. Score Threshold

Require users to reach a minimum score.

```javascript theme={null}
// Encode requirement data
const requirementData = ethers.utils.defaultAbiCoder.encode(
  ['uint256'], // minimum score
  [500]
);

// Create achievement
await contract.createAchievement(
  'Rising Star',
  'Reach a ZKScore of 500',
  'ipfs://QmXyz.../rising-star.png',
  6, // Identity category
  1, // Uncommon rarity
  75, // 75 points
  150, // 1.5% boost
  1, // SCORE_THRESHOLD type
  requirementData
);
```

### 2. Category Score

Require minimum score in a specific category.

```javascript theme={null}
// Encode requirement: category index and minimum score
const requirementData = ethers.utils.defaultAbiCoder.encode(
  ['uint8', 'uint256'],
  [0, 300] // DeFi category, 300 minimum
);

await contract.createAchievement(
  'DeFi Expert',
  'Reach 300 DeFi score',
  'ipfs://QmXyz.../defi-expert.png',
  0, // DeFi category
  2, // Rare
  150,
  300,
  2, // CATEGORY_SCORE type
  requirementData
);
```

### 3. Activity Count

Require a certain number of activities.

```javascript theme={null}
// Encode requirement: activity type and count
const requirementData = ethers.utils.defaultAbiCoder.encode(
  ['bytes32', 'uint256'],
  [
    ethers.utils.id('NFT_TRADE'), // activity type hash
    50 // required count
  ]
);

await contract.createAchievement(
  'Active Trader',
  'Complete 50 NFT trades',
  'ipfs://QmXyz.../active-trader.png',
  1, // NFT category
  1, // Uncommon
  100,
  200,
  3, // ACTIVITY_COUNT type
  requirementData
);
```

### 4. Time-Based

Require users to be active for a certain duration.

```javascript theme={null}
// Encode requirement: duration in seconds
const requirementData = ethers.utils.defaultAbiCoder.encode(
  ['uint256'],
  [180 * 24 * 60 * 60] // 180 days
);

await contract.createAchievement(
  'Veteran Member',
  'Be active for 6 months',
  'ipfs://QmXyz.../veteran.png',
  6, // Identity category
  2, // Rare
  200,
  400,
  4, // TIME_BASED type
  requirementData
);
```

### 5. Composite

Combine multiple requirements.

```javascript theme={null}
// Encode multiple requirements
const requirementData = ethers.utils.defaultAbiCoder.encode(
  ['uint8[]', 'uint256[]'],
  [
    [0, 1, 2], // Categories: DeFi, NFT, Social
    [200, 200, 200] // Minimum scores for each
  ]
);

await contract.createAchievement(
  'Well-Rounded',
  'Score 200+ in DeFi, NFT, and Social',
  'ipfs://QmXyz.../well-rounded.png',
  6, // Identity category
  3, // Epic
  400,
  800,
  5, // COMPOSITE type
  requirementData
);
```

### 6. Proof-Based

Require zero-knowledge proof verification.

```javascript theme={null}
// Encode proof verification parameters
const requirementData = ethers.utils.defaultAbiCoder.encode(
  ['address', 'bytes32'],
  [
    '0xVerifierContractAddress',
    ethers.utils.id('PROTOCOL_PARTICIPATION')
  ]
);

await contract.createAchievement(
  'Privacy Champion',
  'Verify protocol participation with ZK proof',
  'ipfs://QmXyz.../privacy-champion.png',
  7, // Trust category
  4, // Legendary
  1000,
  2000,
  6, // PROOF_BASED type
  requirementData
);
```

## Complete Creation Example

### DeFi Protocol Achievement

<CodeGroup>
  ```javascript JavaScript theme={null}
  const { ethers } = require('ethers');

  async function createDeFiAchievement() {
    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
    );
    
    // Achievement parameters
    const name = 'Liquidity Provider Pro';
    const description = 'Provide liquidity across 5 different protocols';
    const imageURI = 'ipfs://QmXyz.../lp-pro.png';
    const category = 0; // DeFi
    const rarity = 2; // Rare
    const points = 200;
    const scoreBoost = 400; // 4%
    
    // Encode requirement: 5 different protocols
    const requirementData = ethers.utils.defaultAbiCoder.encode(
      ['bytes32', 'uint256'],
      [
        ethers.utils.id('LIQUIDITY_PROVIDED'),
        5 // 5 protocols
      ]
    );
    
    const requirementType = 3; // ACTIVITY_COUNT
    
    // Create achievement
    const tx = await contract.createAchievement(
      name,
      description,
      imageURI,
      category,
      rarity,
      points,
      scoreBoost,
      requirementType,
      requirementData
    );
    
    const receipt = await tx.wait();
    
    // Get achievement ID from event
    const event = receipt.events.find(e => e.event === 'AchievementCreated');
    const achievementId = event.args.achievementId;
    
    console.log(`Achievement created!`);
    console.log(`ID: ${achievementId.toString()}`);
    console.log(`Name: ${name}`);
    console.log(`Category: DeFi`);
    console.log(`Rarity: Rare`);
    console.log(`Points: ${points}`);
    console.log(`Boost: ${scoreBoost / 100}%`);
    
    return achievementId;
  }
  ```

  ```python Python theme={null}
  from web3 import Web3
  from eth_abi import encode

  def create_defi_achievement():
      w3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/YOUR_KEY'))
      
      contract = w3.eth.contract(
          address='0x3456789012345678901234567890123456789012',
          abi=ACHIEVEMENT_REGISTRY_ABI
      )
      
      account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')
      
      # Achievement parameters
      name = 'Liquidity Provider Pro'
      description = 'Provide liquidity across 5 different protocols'
      image_uri = 'ipfs://QmXyz.../lp-pro.png'
      category = 0  # DeFi
      rarity = 2  # Rare
      points = 200
      score_boost = 400  # 4%
      
      # Encode requirement: 5 different protocols
      activity_type = w3.keccak(text='LIQUIDITY_PROVIDED')
      requirement_data = encode(['bytes32', 'uint256'], [activity_type, 5])
      
      requirement_type = 3  # ACTIVITY_COUNT
      
      # Create achievement
      tx = contract.functions.createAchievement(
          name,
          description,
          image_uri,
          category,
          rarity,
          points,
          score_boost,
          requirement_type,
          requirement_data
      ).buildTransaction({
          'from': account.address,
          'gas': 250000,
          'gasPrice': w3.eth.gas_price,
          'nonce': w3.eth.get_transaction_count(account.address)
      })
      
      signed_tx = w3.eth.account.sign_transaction(tx, account.key)
      tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
      
      receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
      
      # Get achievement ID from event
      event = contract.events.AchievementCreated().processReceipt(receipt)[0]
      achievement_id = event['args']['achievementId']
      
      print(f"Achievement created!")
      print(f"ID: {achievement_id}")
      print(f"Name: {name}")
      print(f"Category: DeFi")
      print(f"Rarity: Rare")
      print(f"Points: {points}")
      print(f"Boost: {score_boost / 100}%")
      
      return achievement_id
  ```
</CodeGroup>

## Metadata Best Practices

### Image Guidelines

1. **Format**: PNG with transparency
2. **Size**: 512x512 pixels minimum
3. **Style**: Consistent with your brand
4. **Quality**: High resolution for badges
5. **Storage**: IPFS or decentralized storage

### Creating Badge Images

```javascript theme={null}
// Upload to IPFS
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');

async function uploadBadgeToIPFS(imagePath) {
  const formData = new FormData();
  formData.append('file', fs.createReadStream(imagePath));
  
  const response = await axios.post(
    'https://api.pinata.cloud/pinning/pinFileToIPFS',
    formData,
    {
      headers: {
        'Authorization': `Bearer ${process.env.PINATA_JWT}`,
        ...formData.getHeaders()
      }
    }
  );
  
  const ipfsHash = response.data.IpfsHash;
  const imageURI = `ipfs://${ipfsHash}`;
  
  console.log(`Badge uploaded: ${imageURI}`);
  return imageURI;
}
```

### Description Guidelines

1. **Length**: 50-150 characters
2. **Clarity**: Clear requirements
3. **Tone**: Encouraging and positive
4. **Action**: Describe what to do
5. **Benefit**: Mention rewards

## Verification Setup

### Manual Verification

For achievements requiring manual review:

```javascript theme={null}
class ManualVerifier {
  constructor(contract, account) {
    this.contract = contract;
    this.account = account;
  }
  
  async verifyUser(userAddress, achievementId, proofData) {
    // Verify proof data
    const isValid = await this.validateProof(proofData);
    
    if (!isValid) {
      throw new Error('Invalid proof data');
    }
    
    // Update progress to 100%
    const achievement = await this.contract.getAchievement(achievementId);
    const requiredProgress = achievement.requirementData; // depends on type
    
    await this.contract.updateProgress(
      userAddress,
      achievementId,
      requiredProgress
    );
    
    console.log(`User ${userAddress} verified for achievement ${achievementId}`);
  }
  
  async validateProof(proofData) {
    // Implement your validation logic
    return true;
  }
}
```

### Automatic Verification

For automated achievements:

```javascript theme={null}
class AutomaticVerifier {
  constructor(contract) {
    this.contract = contract;
  }
  
  // Listen for relevant events
  async monitorActivity(userAddress, activityType) {
    // Monitor blockchain events
    const filter = {
      address: PROTOCOL_ADDRESS,
      topics: [
        ethers.utils.id(activityType),
        ethers.utils.hexZeroPad(userAddress, 32)
      ]
    };
    
    provider.on(filter, async (log) => {
      await this.incrementProgress(userAddress, log);
    });
  }
  
  async incrementProgress(userAddress, log) {
    // Parse event data
    const eventData = parseEventLog(log);
    
    // Update achievement progress
    const achievementIds = await this.getRelatedAchievements(eventData.type);
    
    for (const id of achievementIds) {
      const currentProgress = await this.contract.getProgress(userAddress, id);
      const newProgress = currentProgress.current + 1;
      
      await this.contract.updateProgress(userAddress, id, newProgress);
    }
  }
  
  async getRelatedAchievements(activityType) {
    // Return achievement IDs that track this activity
    return [123, 456, 789];
  }
}
```

## Testing Custom Achievements

### Testing on Testnet

```javascript theme={null}
async function testAchievement(achievementId) {
  // 1. Create test user
  const testUser = ethers.Wallet.createRandom().connect(provider);
  
  // 2. Fund test user
  await signer.sendTransaction({
    to: testUser.address,
    value: ethers.utils.parseEther('0.1')
  });
  
  // 3. Check initial progress
  const initialProgress = await contract.getProgress(testUser.address, achievementId);
  console.log('Initial progress:', initialProgress);
  
  // 4. Simulate activity (update progress)
  await contract.updateProgress(testUser.address, achievementId, 100);
  
  // 5. Verify can claim
  const canClaim = await contract.canClaim(testUser.address, achievementId);
  console.log('Can claim:', canClaim);
  
  // 6. Claim achievement
  const contractWithTestUser = contract.connect(testUser);
  const tx = await contractWithTestUser.claimAchievement(achievementId, '0x');
  await tx.wait();
  
  console.log('✅ Achievement successfully claimed in test!');
}
```

## Batch Achievement Creation

### Creating Multiple Achievements

```javascript theme={null}
async function createAchievementSeries() {
  const achievements = [
    {
      name: 'First Trade',
      description: 'Complete your first trade',
      category: 3,
      rarity: 0,
      points: 10,
      requirement: { type: 'ACTIVITY_COUNT', count: 1 }
    },
    {
      name: 'Active Trader',
      description: 'Complete 10 trades',
      category: 3,
      rarity: 1,
      points: 50,
      requirement: { type: 'ACTIVITY_COUNT', count: 10 }
    },
    {
      name: 'Trading Master',
      description: 'Complete 100 trades',
      category: 3,
      rarity: 2,
      points: 200,
      requirement: { type: 'ACTIVITY_COUNT', count: 100 }
    }
  ];
  
  const createdIds = [];
  
  for (const ach of achievements) {
    const requirementData = ethers.utils.defaultAbiCoder.encode(
      ['bytes32', 'uint256'],
      [ethers.utils.id('TRADE_COMPLETED'), ach.requirement.count]
    );
    
    const tx = await contract.createAchievement(
      ach.name,
      ach.description,
      `ipfs://QmXyz.../${ach.name.toLowerCase().replace(/\s/g, '-')}.png`,
      ach.category,
      ach.rarity,
      ach.points,
      ach.points * 2, // 2x points as boost
      3, // ACTIVITY_COUNT
      requirementData
    );
    
    const receipt = await tx.wait();
    const event = receipt.events.find(e => e.event === 'AchievementCreated');
    
    createdIds.push(event.args.achievementId.toString());
    console.log(`Created: ${ach.name} (ID: ${event.args.achievementId.toString()})`);
  }
  
  return createdIds;
}
```

## Best Practices

### Achievement Design

1. **Progressive Difficulty**: Create series with increasing difficulty
2. **Clear Requirements**: Make requirements obvious
3. **Balanced Rewards**: Match rewards to difficulty
4. **Category Alignment**: Ensure category matches activity
5. **Unique Names**: Use descriptive, unique names

### Implementation

1. **Test Thoroughly**: Test on testnet first
2. **Monitor Events**: Track creation and claim events
3. **Update Documentation**: Document custom achievements
4. **User Communication**: Announce new achievements
5. **Gather Feedback**: Iterate based on user feedback

### Verification

1. **Secure Verification**: Protect verification endpoints
2. **Prevent Gaming**: Implement anti-cheat measures
3. **Audit Logs**: Maintain verification logs
4. **Regular Reviews**: Review achievement completion
5. **Fair Distribution**: Ensure fair access

## Related Documentation

* [Contract Overview](/contracts/achievement-registry/overview) - Contract architecture
* [Functions Reference](/contracts/achievement-registry/functions) - Function documentation
* [Events Reference](/contracts/achievement-registry/events) - Event documentation
* [Integration Guide](/contracts/achievement-registry/integration) - Integration examples
