원클릭으로
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.
// 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.
x402 HTTP-native payment protocol for AI agents on Celo. Use when implementing pay-per-use APIs, agent micropayments, or HTTP 402 Payment Required flows with stablecoins.
Verify smart contracts on Celo. Use when publishing contract source code to Celoscan or Blockscout.
Integrate wallets into Celo dApps. Covers RainbowKit, Dynamic, and wallet connection patterns.
Pay gas fees with ERC-20 tokens on Celo. Covers supported tokens, implementation, and wallet compatibility.
Use viem for Celo development. Includes fee currency support, transaction signing, and Celo-specific configurations.
Use wagmi React hooks for Celo dApps. Includes wallet connection, transaction hooks, and React integration patterns.
| name | 8004 |
| description | 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. |
| license | Apache-2.0 |
| metadata | {"author":"celo-org","version":"1.0.0"} |
ERC-8004 establishes trust infrastructure for autonomous AI agents, enabling them to discover, identify, and evaluate other agents across organizational boundaries.
| 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 |
Application Layer (Agent Apps, Marketplaces)
↓
Trust Layer (ERC-8004) ← This skill
↓
Payment Layer (x402)
↓
Communication Layer (A2A, MCP)
npm install viem
ABIs are available at
skills/8004/references/identity-registry-abi.jsonandskills/8004/references/reputation-registry-abi.json.
| Contract | Address |
|---|---|
| Identity Registry | 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 |
| Reputation Registry | 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 |
| Contract | Address |
|---|---|
| Identity Registry | 0x8004A818BFB912233c491871b3d84c89A494BD9e |
| Reputation Registry | 0x8004B663056A597Dffe9eCcC1965A193B7388713 |
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'),
});
Create an agent metadata JSON and host it (IPFS, HTTPS, etc.):
{
"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"]
}
// 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);
// 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'],
});
// 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')],
});
Note: Self-feedback is blocked — the agent owner/operators cannot give feedback to their own agent. The
valuefield isint128(supports negative scores).valueDecimalsmax is 18.
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
],
});
| 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 at a specific index (1-indexed)
await walletClient.writeContract({
address: REPUTATION_REGISTRY,
abi: reputationRegistryAbi,
functionName: 'revokeFeedback',
args: [agentId, 1n], // feedbackIndex (uint64, 1-indexed)
});
Agents (or anyone) can append responses to feedback entries:
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
],
});
// 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)`);
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;
}
ERC-8004 and x402 work together for trustworthy paid agent interactions:
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();
}
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 |
| Network | Chain ID | RPC Endpoint |
|---|---|---|
| Celo Mainnet | 42220 | https://forno.celo.org |
| Celo Sepolia | 11142220 | https://forno.celo-sepolia.celo-testnet.org |