# 8004

> ERC-8004 Agent Trust Protocol for AI agent identity, reputation, and validation on Celo. Use when building AI agents that need identity registration, reputation tracking, or trust verification across organizational boundaries.

- Skill: `celo-org/8004` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add celo-org/8004`
- Raw SKILL.md: https://api.skillmd.com/api/skills/celo-org/8004/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: Apache-2.0
- Author: celo-org (https://skillmd.com/u/celo-org)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/celo-org/8004

---


# ERC-8004: Agent Trust Protocol

ERC-8004 establishes trust infrastructure for autonomous AI agents, enabling them to discover, identify, and evaluate other agents across organizational boundaries.

## When to Use

- Registering an AI agent's identity on-chain
- Building reputation systems for AI agents
- Verifying agent identity before interactions
- Querying agent reputation and feedback
- Implementing trust-based agent interactions

## Core Concepts

### The Three Registries

| Registry | Purpose | Key Functions |
|----------|---------|---------------|
| **Identity Registry** | Agent discovery via ERC-721 NFTs | `register()`, `tokenURI()`, `getAgentWallet()`, `setMetadata()`, `getMetadata()` |
| **Reputation Registry** | Feedback and attestations | `giveFeedback()`, `revokeFeedback()`, `readFeedback()`, `readAllFeedback()`, `getSummary()`, `appendResponse()`, `getClients()` |
| **Validation Registry** | Verification hooks | Custom validators |

### Protocol Stack Position

```
Application Layer (Agent Apps, Marketplaces)
    ↓
Trust Layer (ERC-8004) ← This skill
    ↓
Payment Layer (x402)
    ↓
Communication Layer (A2A, MCP)
```

## Installation

```bash
npm install viem
```

> ABIs are available at `skills/8004/references/identity-registry-abi.json` and `skills/8004/references/reputation-registry-abi.json`.

## Contract Addresses

### Celo Mainnet (Chain ID: 42220)

| Contract | Address |
|----------|---------|
| Identity Registry | `0x8004A169FB4a3325136EB29fA0ceB6D2e539a432` |
| Reputation Registry | `0x8004BAa17C55a88189AE136b182e5fdA19dE9b63` |

### Celo Sepolia Testnet (Chain ID: 11142220)

| Contract | Address |
|----------|---------|
| Identity Registry | `0x8004A818BFB912233c491871b3d84c89A494BD9e` |
| Reputation Registry | `0x8004B663056A597Dffe9eCcC1965A193B7388713` |

## Setup (viem)

```javascript
import { createPublicClient, createWalletClient, http, getContract } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { celo, celoAlfajores } from 'viem/chains';
import identityRegistryAbi from './references/identity-registry-abi.json';
import reputationRegistryAbi from './references/reputation-registry-abi.json';

// Celo Mainnet addresses
const IDENTITY_REGISTRY = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432';
const REPUTATION_REGISTRY = '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';

// Celo Sepolia Testnet addresses
// const IDENTITY_REGISTRY = '0x8004A818BFB912233c491871b3d84c89A494BD9e';
// const REPUTATION_REGISTRY = '0x8004B663056A597Dffe9eCcC1965A193B7388713';

const account = privateKeyToAccount('0xYOUR_PRIVATE_KEY');

const publicClient = createPublicClient({
  chain: celo,
  transport: http('https://forno.celo.org'),
});

const walletClient = createWalletClient({
  account,
  chain: celo,
  transport: http('https://forno.celo.org'),
});
```

## Agent Registration

### 1. Agent Metadata Format

Create an agent metadata JSON and host it (IPFS, HTTPS, etc.):

```json
{
  "type": "Agent",
  "name": "My AI Agent",
  "description": "Description of capabilities",
  "image": "ipfs://Qm...",
  "endpoints": [
    { "type": "a2a", "url": "https://example.com/.well-known/agent.json" },
    { "type": "mcp", "url": "https://example.com/mcp" },
    { "type": "wallet", "address": "0x...", "chainId": 42220 }
  ],
  "supportedTrust": ["reputation", "validation", "tee"]
}
```

### 2. Register Agent On-Chain

```javascript
// Register without URI (minimal)
const hash = await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'register',
  args: [],
});

// Register with metadata URI
const hash = await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'register',
  args: ['ipfs://QmYourAgentMetadata'],
});

// Register with URI + custom metadata key-value pairs
const hash = await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'register',
  args: [
    'ipfs://QmYourAgentMetadata',
    [
      { metadataKey: 'category', metadataValue: '0x' + Buffer.from('defi-trading').toString('hex') },
      { metadataKey: 'version', metadataValue: '0x' + Buffer.from('1.0.0').toString('hex') },
    ],
  ],
});

// Get agent ID from transaction receipt
const receipt = await publicClient.waitForTransactionReceipt({ hash });
const transferLog = receipt.logs.find(log => log.topics.length === 4); // Transfer event
const agentId = BigInt(transferLog.topics[3]); // tokenId is the 3rd indexed param
console.log('Agent registered with ID:', agentId);
```

### 3. Read Agent Data

```javascript
// Get agent metadata URI
const agentURI = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'tokenURI',
  args: [agentId],
});

// Get agent wallet address
const agentWallet = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'getAgentWallet',
  args: [agentId],
});

// Get agent owner (NFT holder)
const owner = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'ownerOf',
  args: [agentId],
});

// Get custom metadata
const categoryBytes = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'getMetadata',
  args: [agentId, 'category'],
});
```

### 4. Update Agent

```javascript
// Update agent URI
await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'setAgentURI',
  args: [agentId, 'ipfs://QmUpdatedMetadata'],
});

// Set custom metadata
await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'setMetadata',
  args: [agentId, 'status', '0x' + Buffer.from('active').toString('hex')],
});
```

## Reputation System

### Give Feedback

> **Note:** Self-feedback is blocked — the agent owner/operators cannot give feedback to their own agent. The `value` field is `int128` (supports negative scores). `valueDecimals` max is 18.

```javascript
import { keccak256, toBytes } from 'viem';

const feedbackContent = JSON.stringify({ quality: 'excellent', notes: 'Fast response' });
const feedbackHash = keccak256(toBytes(feedbackContent));

await walletClient.writeContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'giveFeedback',
  args: [
    agentId,                              // agentId (uint256)
    85n,                                  // value (int128) — can be negative
    0,                                    // valueDecimals (uint8)
    'starred',                            // tag1: category
    '',                                   // tag2: optional sub-category
    'https://agent.example.com',          // endpoint used
    'ipfs://QmDetailedFeedback',          // feedbackURI for details
    feedbackHash,                         // keccak256 of feedback content
  ],
});
```

### Common Feedback Tags

| Tag | Measures | Example |
|-----|----------|---------|
| `starred` | Quality rating (0-100) | 87/100 |
| `uptime` | Endpoint uptime % | 99.77% |
| `successRate` | Task success rate % | 89% |
| `responseTime` | Response time (ms) | 560ms |
| `reachable` | Endpoint reachable | 1/0 |

### Revoke Feedback

```javascript
// Revoke feedback at a specific index (1-indexed)
await walletClient.writeContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'revokeFeedback',
  args: [agentId, 1n], // feedbackIndex (uint64, 1-indexed)
});
```

### Respond to Feedback

Agents (or anyone) can append responses to feedback entries:

```javascript
await walletClient.writeContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'appendResponse',
  args: [
    agentId,
    clientAddress,        // address of feedback author
    1n,                   // feedbackIndex
    'ipfs://QmResponse',  // responseURI
    responseHash,         // keccak256 of response content
  ],
});
```

### Query Reputation

```javascript
// Get all clients who gave feedback
const clients = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'getClients',
  args: [agentId],
});

// Read a single feedback entry
const [value, valueDecimals, tag1, tag2, isRevoked] = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'readFeedback',
  args: [agentId, clientAddress, 1n], // feedbackIndex (1-indexed)
});

// Read all feedback (pass clients array, filter by tags)
const allFeedback = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'readAllFeedback',
  args: [
    agentId,
    clients,    // clientAddresses — pass [] to auto-use all known clients
    '',         // tag1 filter ('' = all)
    '',         // tag2 filter ('' = all)
    false,      // includeRevoked
  ],
});
// Returns: { clients, feedbackIndexes, values, valueDecimals, tag1s, tag2s, revokedStatuses }

// Get aggregated summary (requires clientAddresses)
const [count, summaryValue, summaryValueDecimals] = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'getSummary',
  args: [
    agentId,
    clients,  // clientAddresses (required, cannot be empty)
    '',       // tag1 filter
    '',       // tag2 filter
  ],
});
console.log(`Average: ${summaryValue} (${count} reviews, ${summaryValueDecimals} decimals)`);
```

## Trust Verification Workflow

```javascript
async function verifyAndInteract(targetAgentId, minScore = 70n) {
  // 1. Verify identity exists (reverts if not)
  const owner = await publicClient.readContract({
    address: IDENTITY_REGISTRY,
    abi: identityRegistryAbi,
    functionName: 'ownerOf',
    args: [targetAgentId],
  });

  // 2. Get clients and check reputation
  const clients = await publicClient.readContract({
    address: REPUTATION_REGISTRY,
    abi: reputationRegistryAbi,
    functionName: 'getClients',
    args: [targetAgentId],
  });

  if (clients.length > 0) {
    const [count, summaryValue] = await publicClient.readContract({
      address: REPUTATION_REGISTRY,
      abi: reputationRegistryAbi,
      functionName: 'getSummary',
      args: [targetAgentId, clients, '', ''],
    });
    if (summaryValue < minScore) {
      throw new Error(`Agent reputation ${summaryValue} below threshold ${minScore}`);
    }
  }

  // 3. Fetch agent metadata and find endpoint
  const agentURI = await publicClient.readContract({
    address: IDENTITY_REGISTRY,
    abi: identityRegistryAbi,
    functionName: 'tokenURI',
    args: [targetAgentId],
  });
  const agentData = await fetch(agentURI).then(r => r.json());
  const endpoint = agentData.endpoints.find(e => e.type === 'a2a');

  // 4. Interact with verified agent
  const result = await interactWithAgent(endpoint.url);

  // 5. Submit feedback
  await walletClient.writeContract({
    address: REPUTATION_REGISTRY,
    abi: reputationRegistryAbi,
    functionName: 'giveFeedback',
    args: [
      targetAgentId,
      result.success ? 90n : 30n,
      0,
      result.success ? 'starred' : 'failed',
      '',
      endpoint.url,
      '',
      '0x0000000000000000000000000000000000000000000000000000000000000000',
    ],
  });

  return result;
}
```

## Integration with x402 Payments

ERC-8004 and x402 work together for trustworthy paid agent interactions:

```javascript
import { wrapFetchWithPayment } from 'thirdweb/x402';

async function payTrustedAgent(agentId, serviceUrl) {
  // 1. Verify trust via reputation
  const clients = await publicClient.readContract({
    address: REPUTATION_REGISTRY,
    abi: reputationRegistryAbi,
    functionName: 'getClients',
    args: [agentId],
  });

  if (clients.length > 0) {
    const [count, summaryValue] = await publicClient.readContract({
      address: REPUTATION_REGISTRY,
      abi: reputationRegistryAbi,
      functionName: 'getSummary',
      args: [agentId, clients, '', ''],
    });
    if (summaryValue < 80n) {
      throw new Error('Agent not trusted enough for payment');
    }
  }

  // 2. Make paid request via x402
  const fetchWithPayment = wrapFetchWithPayment({
    client,
    account,
    paymentOptions: { maxValue: "1000000" },
  });

  const response = await fetchWithPayment(serviceUrl);
  return response.json();
}
```

## Validation Registry

For high-stakes operations, use Validation Registry for additional verification:

| Model | Mechanism | Best For |
|-------|-----------|----------|
| **Reputation-based** | Client feedback | Low-stake, frequent |
| **Crypto-economic** | Stake + slashing | Medium-stake financial |
| **zkML** | Zero-knowledge proofs | Privacy-preserving |
| **TEE Attestation** | Hardware isolation | High-assurance |

## Celo Network Reference

| Network | Chain ID | RPC Endpoint |
|---------|----------|--------------|
| Celo Mainnet | 42220 | https://forno.celo.org |
| Celo Sepolia | 11142220 | https://forno.celo-sepolia.celo-testnet.org |

## Additional Resources

- [EIP Specification](https://eips.ethereum.org/EIPS/eip-8004)
- [Official Website](https://www.8004.org)
- [Learning Portal](https://www.8004.org/learn)
- [Contracts Repository](https://github.com/erc-8004/erc-8004-contracts)
- [Builder Program](http://bit.ly/8004builderprogram)

## Related Skills

- [x402](../x402/SKILL.md) - Payment layer for AI agents
- [celo-rpc](../celo-rpc/SKILL.md) - Celo blockchain interaction
- [viem](../viem/SKILL.md) - TypeScript Ethereum library

