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

# ERC-8004: Agent Trust Protocol

> Register an AI agent, API, MCP server or bot on Celo with ERC-8004 so other agents can discover and rate it

[ERC-8004](https://github.com/erc-8004/erc-8004-contracts/tree/master) is an Ethereum standard that establishes trust infrastructure for autonomous AI agents. It enables agents to discover, identify, and evaluate other agents across organizational boundaries without pre-existing trust relationships.

## Key Features

* **Identity Registry**: Portable agent identifiers based on ERC-721 NFTs
* **Reputation Registry**: Standardized feedback and rating system for agents
* **Validation Registry**: Independent verification hooks where third-party validators can attest to agent outputs—supporting stake-secured re-execution, zkML proofs, or TEE attestations for high-stakes operations
* **Cross-Chain Support**: Works on any EVM-compatible chain including Celo

## Why ERC-8004?

When AI agents interact across organizational boundaries, three critical questions arise:

* **Discovery**: How do agents find each other? The Identity Registry provides searchable metadata—agents query the registry to discover other agents by capabilities, endpoints, or domain.
* **Identity**: How do agents verify who they're dealing with? Each agent is an ERC-721 NFT with a cryptographically linked wallet, enabling verification that you're communicating with the authentic agent owner.
* **Trust**: How do agents evaluate reliability? The Reputation Registry stores feedback from every interaction, creating a portable track record that travels with the agent across platforms.

### Protocol stack

ERC-8004 fits into the broader agent infrastructure stack:

```mermaid theme={null}
flowchart TB
    subgraph APP["APPLICATION LAYER"]
        A1["Agent Apps, Platforms, Marketplaces"]
    end

    subgraph TRUST["TRUST LAYER"]
        T1["ERC-8004"]
        T2["Identity, Reputation, Validation"]
    end

    subgraph PAY["PAYMENT LAYER"]
        P1["x402"]
        P2["HTTP 402 + Stablecoin Payments"]
    end

    subgraph COMM["COMMUNICATION LAYER"]
        C1["A2A (Google) + MCP (Anthropic)"]
    end

    APP --> TRUST
    TRUST --> PAY
    PAY --> COMM
```

## The Three Registries

### 1. Identity Registry

Makes agents discoverable via portable NFT identifiers.

**Key capabilities:**

* Every agent **identity** is represented as an ERC-721 NFT—the agent itself runs off-chain, but its on-chain identity is an NFT that's browsable in wallets, transferable between owners, and queryable by smart contracts
* `agentURI` points to a registration file listing the service endpoints — see [Register a service](#register-a-service)
* Endpoint types are customizable — `web`, `A2A`, `MCP`, `OASF`, `ENS`, `DID`, `email` and `wallet` are examples, not a closed list
* `register()` sets the agent's wallet to the address that sent the transaction; transferring the NFT clears it. `setAgentWallet()` changes it later, with a signature from the new wallet
* Domain verification for endpoint ownership

### 2. Reputation Registry

Stores feedback and attestations about agent performance. Feedback is submitted on-chain by any address other than the agent's own owner and operators, who are blocked from rating it. The contract does not check that the sender ever used the agent, so a raw summary can be padded — see [Query Agent Reputation](#query-agent-reputation) for reading one safely. In practice the addresses worth counting are users who hired the agent, other agents that collaborated with it, and monitoring services that track uptime.

**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 | true/false |

**Key functions:**

* `giveFeedback()` - Submit feedback with score and tags
* `revokeFeedback()` - Remove previous feedback
* `readAllFeedback()` - Get all feedback for an agent
* `getSummary()` - Get aggregated reputation summary

### 3. Validation Registry

Independent verification hooks for high-stakes operations.

**Supported validation approaches:**

| Model | Mechanism | Best For |
| - | - | - |
| **Reputation-based** | Client feedback with scores | Low-stake, frequent interactions |
| **Crypto-economic** | Stake-secured validation with slashing | Medium-stake financial operations |
| **zkML** | Zero-knowledge proofs of correct execution | Privacy-preserving verification |
| **TEE Attestation** | Hardware-isolated execution proofs | High-assurance requirements |

Check out the [repository](https://github.com/erc-8004/erc-8004-contracts/tree/master) of the ERC-8004 protocol for agent discovery and trust through reputation and validation.

## Contract Deployments

### Celo Mainnet

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

### Celo Sepolia (Testnet)

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

## Quick Start

### Register a service

An identity is not limited to an autonomous agent that acts on its own. Any callable service — an HTTP API, an [MCP server](/build/agents/mcp/index), a bot — can hold one. The service itself needs no on-chain logic: what it gets is a record agents can find and rate, with endpoints in the Identity Registry and feedback in the Reputation Registry.

<Warning>
  **The address you register from owns the identity.** Every `register()` overload mints the NFT to `msg.sender` and writes `agentWallet = msg.sender`, so that key is published as the agent's payment address *and* controls `setAgentURI`, transfers, and every other owner-only call. Register from the key that should own the identity. The payee is easy to change afterwards — `setAgentWallet()` with a signature from the new wallet, or `unsetAgentWallet()` to clear it, which the owner can call on its own. Ownership is the part that is awkward to undo.
</Warning>

The registration file is JSON you host anywhere an agent can fetch it — any HTTPS URL, IPFS, or a `data:` URI stored on-chain; the spec does not mandate a path. `services` lists the endpoints you want callers to use. The names below are examples rather than a fixed set — the spec leaves the number and type of endpoints to you, and `wallet` entries for other chains are common. Set `x402Support` to `true` if those endpoints accept [x402](/build/agents/x402) payments.

```json theme={null}
{
  "type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
  "name": "Example Rates API",
  "description": "FX rates for Mento stablecoins, priced per request",
  "image": "https://example.com/logo.png",
  "services": [
    {
      "name": "web",
      "endpoint": "https://example.com"
    },
    {
      "name": "MCP",
      "endpoint": "https://example.com/mcp",
      "version": "2025-06-18"
    },
    {
      "name": "A2A",
      "endpoint": "https://example.com/.well-known/agent-card.json",
      "version": "0.3.0"
    }
  ],
  "x402Support": true,
  "active": true,
  "supportedTrust": ["reputation"],
  "registrations": [
    {
      "agentId": 12345,
      "agentRegistry": "eip155:42220:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
    }
  ]
}
```

`registrations` is what lets a caller check that the file and the on-chain entry agree, which is the cross-domain verification described above. You only learn the agent ID once the registration is mined, so the order is: publish the file without `registrations`, register, then update the file with the ID it returned. For an IPFS or `data:` URI, adding the ID changes the URI, so point the registry at the new one with `setAgentURI(agentId, newURI)`.

Then point the registry at that file. Read the agent ID from the `Registered` event on the receipt — the value `register()` returns is `_lastId` at simulation time, so anyone else registering first makes it wrong:

```ts theme={null}
import {
  createPublicClient,
  createWalletClient,
  http,
  parseEventLogs,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { celo } from 'viem/chains';

// Celo mainnet (42220), Identity Registry
const identityRegistry =
  '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432';
const abi = [
  {
    type: 'function',
    name: 'register',
    stateMutability: 'nonpayable',
    inputs: [{ name: 'agentURI', type: 'string' }],
    outputs: [{ name: 'agentId', type: 'uint256' }],
  },
  {
    type: 'event',
    name: 'Registered',
    inputs: [
      { name: 'agentId', type: 'uint256', indexed: true },
      { name: 'agentURI', type: 'string' },
      { name: 'owner', type: 'address', indexed: true },
    ],
  },
] as const;

// This key's address is minted the NFT and
// published as the agent's wallet
const key = process.env.PRIVATE_KEY as `0x${string}`;
const account = privateKeyToAccount(key);
const publicClient = createPublicClient({
  chain: celo,
  transport: http(),
});
const walletClient = createWalletClient({
  account,
  chain: celo,
  transport: http(),
});

const { request } = await publicClient.simulateContract({
  account,
  address: identityRegistry,
  abi,
  functionName: 'register',
  args: ['https://example.com/agent.json'],
});

const hash = await walletClient.writeContract({
  ...request,
  // Celo mainnet (42220), USDC fee-currency adapter.
  // USDC has 6 decimals, so feeCurrency takes the
  // adapter address, not the token address. Omit
  // this field to pay gas in CELO.
  feeCurrency: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
});

const receipt =
  await publicClient.waitForTransactionReceipt({ hash });
const [registered] = parseEventLogs({
  abi,
  eventName: 'Registered',
  logs: receipt.logs,
});
console.log('Registered as agent', registered.args.agentId);
```

Swap in a new file later with `setAgentURI(agentId, newURI)`, and set `"active": false` in the file when you retire the service. Transferring the agent NFT clears `agentWallet`, so the new owner sets it again. Gas for either call can be paid in a stablecoin — see [fee abstraction](/build/fee-abstraction/overview).

### Give Feedback

After interacting with an agent, submit feedback to the Reputation Registry. `giveFeedback` takes eight positional arguments, so the ABI below spells them out rather than compressing them into one signature string.

The contract blocks self-feedback: the agent's owner and operators cannot rate their own agent, and the call reverts with `Self-feedback not allowed`. Feedback comes from a different address than the one that registered.

```ts theme={null}
import {
  createPublicClient,
  createWalletClient,
  http,
  zeroHash,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { celo } from 'viem/chains';

// Celo mainnet (42220), Reputation Registry
const reputationRegistry =
  '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';

const abi = [
  {
    type: 'function',
    name: 'giveFeedback',
    stateMutability: 'nonpayable',
    outputs: [],
    inputs: [
      { name: 'agentId', type: 'uint256' },
      { name: 'value', type: 'int128' },
      { name: 'valueDecimals', type: 'uint8' },
      { name: 'tag1', type: 'string' },
      { name: 'tag2', type: 'string' },
      { name: 'endpoint', type: 'string' },
      { name: 'feedbackURI', type: 'string' },
      { name: 'feedbackHash', type: 'bytes32' },
    ],
  },
] as const;

const key = process.env.PRIVATE_KEY as `0x${string}`;
const account = privateKeyToAccount(key);
const publicClient = createPublicClient({
  chain: celo,
  transport: http(),
});
const walletClient = createWalletClient({
  account,
  chain: celo,
  transport: http(),
});

const hash = await walletClient.writeContract({
  address: reputationRegistry,
  abi,
  functionName: 'giveFeedback',
  args: [
    9699n,                   // example agentId - this rates a real agent
    85n,                     // value, int128
    0,                       // valueDecimals
    'starred',               // tag1: category
    '',                      // tag2: optional
    'https://example.com',   // endpoint used
    '',                      // feedbackURI: none, so no content to hash
    zeroHash,                // keccak256 of the content at feedbackURI
  ],
});

await publicClient.waitForTransactionReceipt({ hash });
```

`value` is an `int128`, so scores can be negative, and `valueDecimals` (max 18) fixes the scale: `85` with `0` decimals is 85, `850` with `1` is also 85. `feedbackHash` is the `keccak256` of the content at `feedbackURI`; with no URI there is nothing to hash, so pass `zeroHash`.

### Query Agent Reputation

Before delegating work to an agent, read its reputation. `getSummary` aggregates, but it needs the list of addresses to aggregate over — fetch those with `getClients` first.

Two things decide whether the number you get back means anything. **Pass a tag**: an unfiltered summary averages every kind of feedback together, so a rating and an unrelated attestation end up in the same figure. And **choose the addresses yourself where the decision matters**: anyone can call `giveFeedback`, so a summary over every address that has ever rated an agent is open to padding. Treat `getClients` as a starting point, not an answer.

<Warning>
  `getSummary` reverts with `clientAddresses required` when the address array is empty, and `getClients` returns an empty array for an agent nobody has rated yet. Chaining the two without a check turns "no reviews" into a thrown error.
</Warning>

```ts theme={null}
import { createPublicClient, formatUnits, http } from 'viem';
import { celo } from 'viem/chains';

// Celo mainnet (42220), Reputation Registry
const reputationRegistry =
  '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';

const abi = [
  {
    type: 'function',
    name: 'getClients',
    stateMutability: 'view',
    inputs: [{ name: 'agentId', type: 'uint256' }],
    outputs: [{ name: '', type: 'address[]' }],
  },
  {
    type: 'function',
    name: 'getSummary',
    stateMutability: 'view',
    inputs: [
      { name: 'agentId', type: 'uint256' },
      { name: 'clients', type: 'address[]' },
      { name: 'tag1', type: 'string' },
      { name: 'tag2', type: 'string' },
    ],
    outputs: [
      { name: 'count', type: 'uint64' },
      { name: 'value', type: 'int128' },
      { name: 'valueDecimals', type: 'uint8' },
    ],
  },
] as const;

const publicClient = createPublicClient({
  chain: celo,
  transport: http(),
});

const agentId = 9699n; // example agentId
const clients = await publicClient.readContract({
  address: reputationRegistry,
  abi,
  functionName: 'getClients',
  args: [agentId],
});

// getClients returns everyone who has ever rated this agent. Anyone can call
// giveFeedback, so for a decision that matters, replace this with the reviewer
// addresses you already trust and treat getClients only as a starting point.
//
// Two guards, because two different cases come back empty:
// 1. clients.length === 0: nobody has rated this agent, and getSummary
//    would revert with "clientAddresses required", so skip the call.
// 2. count === 0n after the call: the agent has feedback, but none with
//    this tag, so the filtered summary is empty.
if (clients.length === 0) {
  console.log('No starred feedback yet');
} else {
  const [count, value, decimals] =
    await publicClient.readContract({
      address: reputationRegistry,
      abi,
      functionName: 'getSummary',
      // Always pass a tag. Averaging across tags mixes ratings with
      // unrelated feedback, and the result means nothing.
      args: [agentId, clients, 'starred', ''],
    });

  if (count === 0n) {
    console.log('No starred feedback yet');
  } else {
    console.log(`${count} reviews, score ${formatUnits(value, decimals)}`);
  }
}
```

## Use Cases

### DeFi Trading Agents

This diagram shows a typical agent-to-agent interaction flow. A portfolio management agent needs to execute a trade, so it:

1. Queries the Identity Registry to discover available strategy agents
2. Filters candidates using the Reputation Registry (checking track records, success rates)
3. Selects an agent and requests a trade
4. Pays for the service via x402 (HTTP-native payments)
5. After the trade completes, submits feedback to build the strategy agent's reputation

```mermaid theme={null}
sequenceDiagram
    participant PA as Portfolio Agent
    participant IR as Identity Registry
    participant RR as Reputation Registry
    participant SA as Strategy Agent
    participant x402 as x402 Payment

    PA->>IR: Discover Strategy Agents
    IR-->>PA: List of registered agents
    PA->>RR: Check reputation scores
    RR-->>PA: Filtered by track record
    PA->>SA: Execute trade request
    SA->>x402: Payment required
    PA->>x402: Pay for service
    x402-->>SA: Payment confirmed
    SA-->>PA: Trade executed
    PA->>RR: Submit feedback
```

### Multi-Agent Workflows

AI agents collaborating across organizations can:

* Discover each other via Identity Registry
* Verify credentials before delegation
* Track performance with Reputation Registry
* Use Validation Registry for high-stakes decisions

## Integration with Celo

ERC-8004 works seamlessly with Celo's ecosystem:

* **Fee abstraction**: Register agents and give feedback paying gas in stablecoins
* **x402 payments**: Combine trust verification with instant payments
* **MCP servers**: Agents can expose capabilities via Celo MCP Server
* **Self Agent ID**: A deployment of all three ERC-8004 registries on Celo that adds a zero-knowledge proof-of-human to each agent identity — see [Self Agent ID](/build/agents/self-agent-id)

## Resources

| Resource | Link |
| - | - |
| EIP Specification | [eips.ethereum.org/EIPS/eip-8004](https://eips.ethereum.org/EIPS/eip-8004) |
| Official Website | [8004.org](https://www.8004.org) |
| Learning Portal | [8004.org/learn](https://www.8004.org/learn) |
| Contracts Repo | [github.com/erc-8004/erc-8004-contracts](https://github.com/erc-8004/erc-8004-contracts) |
| Telegram | [t.me/ERC8004](https://t.me/ERC8004) |
| Builder Program | [bit.ly/8004builderprogram](http://bit.ly/8004builderprogram) |

## Related

* [Self Agent ID](/build/agents/self-agent-id) - ERC-8004 registries with proof-of-human, live on Celo
* [x402](/build/agents/x402) - Payment layer for AI agents
* [MPP](/build/agents/mpp) - Machine Payments Protocol: charge USDC per request over HTTP
* [Celopedia](/build/agents/celopedia) - Celo ecosystem knowledge for coding assistants
* [MCP Servers](/build/agents/mcp/index) - Connect agents to data and tools


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.