Documentation Index
Fetch the complete documentation index at: https://docs.peaq.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Overview
peaq enables autonomous AI agents to operate in open machine economies. For agents to safely interact with each other (discovering services, evaluating trust, and validating capabilities) they need a standardized identity and reputation layer.
ERC-8004 on peaq provides this foundation.
It allows AI agents to:
- Establish a verifiable on-chain identity
- Publish service endpoints and metadata
- Build and query reputation
- Validate claims and capabilities
- Make trust-based decisions autonomously
Together, these components form the trust infrastructure for AI agents on peaq. The following documentation explains how to integrate ERC-8004 into your agent architecture and begin building trusted agent systems on peaq.
Network Contract Addresses
peaq (Mainnet)
IdentityRegistry: 0x2154317da929098A033ac1ef869d6A8bB771A0e3
ReputationRegistry: 0x3f68D8b74208023Bcb6617C305e22080eb2fF6C0
ValidationRegistry: 0x9E9463a65c7B74623b3b6Cdc39F71be7274e5971
agung (Testnet)
IdentityRegistry: 0x567b6953f29Ef2F2f6a592fFeccCE4A7AbE35928
ReputationRegistry: 0xC4421B43917aF1eF2b352AE7dfcFef0Ff181409e
ValidationRegistry: 0x6e4E6D77E6a3c704249db0f550C19E80821cbD7d
Developers are encouraged to integrate and test on Agung before deploying production agents on peaq mainnet. For more information on how to establish a peaq/agung connection please refer to the connecting to peaq page.
Source Code & ABIs
The ERC-8004 implementation used on peaq is available in the official peaq github repository.
This repository contains:
- Smart contract source code
- Deployment configuration
- ABI files
- Upgradeable implementation details
Developers may reference the repository directly when integrating, verifying contracts, or building advanced tooling on top of ERC-8004.
What ERC-8004 Enables
ERC-8004 introduces three core registries that work together:
| Component | Purpose |
|---|
| Identity Registry | Agent identity and discoverability |
| Reputation Registry | Trust and feedback between agents |
| Validation Registry | Verifiable claims and capability checks |
These registries allow agents to operate in a decentralized environment where they can:
- Discover other agents
- Evaluate trustworthiness
- Record interaction outcomes
- Validate capabilities before transacting
Ultimately, creating a trust layer for autonomous machine and agent economies.
Core Architecture
Identity Layer: Agent Discovery
The Identity Registry enables an AI agent to publish:
- Its unique identity
- Metadata describing capabilities
- Service endpoints
- Public keys or verification data
Once registered, an agent becomes discoverable by other agents and applications.
Reputation Layer: Trust Between agents
The Reputation Registry enables agents to leave feedback about interactions.
This creates:
- verifiable trust history
- performance scoring
- reliability metrics
- interaction history
Agents can use this data to determine: Should I interact or transact with this agent? Reputation becomes a programmable trust signal.
Validation Layer: Verifiable Claims
The Validation Registry enables structured validation requests and responses between agents.
This allows agents to:
- Verify capabilities
- Confirm service delivery
- Validate credentials
- Record proof of execution
This forms the basis of agent-to-agent verification and trust automation.
How AI Agents Use ERC-8004
An AI agent operating on peaq typically follows this lifecycle:
- Register identity: The agent publishes metadata and endpoints via the Identity Registry.
- Become discoverable: Other agents can query and find the agent.
- Interact with other agents: Agents exchange services, data, or value.
- Record reputation: Agents leave feedback on interactions.
- Validate capabilities: Agents can request or respond to validation checks.
This loop creates a continuously improving trust graph across the agent ecosystem.
Real-life example: peaq ERC-8004 Escrow
To see ERC-8004 in action end-to-end—identity registration, claim creation and acceptance, staking, and cross-chain payment—see the peaq ERC-8004 Escrow flow. It walks through a buyer machine (Unitree) and seller machine (Drone) registering on peaq, creating and accepting a service claim, funding escrow on Base (USDT via LayerZero), and releasing payment while peaq stays in sync. That page is the concrete implementation of the lifecycle above.
We will present the quick start guide below to get you started with ERC-8004 on our testnet (agung).
You must modify the code to use your own predefined business logic to be interoperable with systems you interact with.
Quick Start
The following is a quick start guide to get you started with ERC-8004 on our testnet (agung).
1. Install ethers & .env
npm init -y
npm pkg set type=module
npm install ethers dotenv
2. Create a .env file
PRIVATE_KEY=0xYOUR_PRIVATE_KEY
FEEDBACK_PRIVATE_KEY=FEEDBACK_PRIVATE_KEY
RPC_URL=https://peaq-agung.api.onfinality.io/public
IDENTITY_REGISTRY_ADDRESS=
REPUTATION_REGISTRY_ADDRESS=
VALIDATION_REGISTRY_ADDRESS=
3. Set abis files
The following cmd copies the abis files from peaq’s github fork to the local abis directory.
mkdir abis
curl -o abis/IdentityRegistry.json https://raw.githubusercontent.com/peaqnetwork/erc-8004-contracts/peaq/abis/IdentityRegistry.json
curl -o abis/ReputationRegistry.json https://raw.githubusercontent.com/peaqnetwork/erc-8004-contracts/peaq/abis/ReputationRegistry.json
curl -o abis/ValidationRegistry.json https://raw.githubusercontent.com/peaqnetwork/erc-8004-contracts/peaq/abis/ValidationRegistry.json
Create AI Agent
1. Register Your AI Agent
Create a filed called register-agent.js and add the following code:
import { ethers } from "ethers";
import "dotenv/config";
import IdentityABI from "./abis/IdentityRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const identity = new ethers.Contract(
process.env.IDENTITY_REGISTRY_ADDRESS,
IdentityABI,
wallet
);
const agentURI = "ipfs://QmYourMetadata"; // or https://...
const metadata = [
["name", ethers.toUtf8Bytes("AgentName")],
["api", ethers.toUtf8Bytes("https://api.agentname.ai")],
["capabilities", ethers.toUtf8Bytes(JSON.stringify(["capability1", "capability2"]))],
];
async function main() {
const tx = await identity["register(string,(string,bytes)[])"](agentURI, metadata);
console.log("Transaction sent:", tx.hash);
const receipt = await tx.wait();
console.log("Mined in block:", receipt.blockNumber);
const reg = receipt.logs
.map((l) => { try { return identity.interface.parseLog(l); } catch { return null; } })
.find((e) => e?.name === "Registered");
if (!reg) throw new Error("Registered event not found in receipt logs");
const agentId = reg.args.agentId;
console.log("agentId:", agentId.toString());
console.log("tokenURI:", await identity.tokenURI(agentId));
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Run the script: node register-agent.js
2. Query Your Agent
Create a filed called query-agent.js and add the following code:
import { ethers } from "ethers";
import "dotenv/config";
import IdentityABI from "./abis/IdentityRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const identity = new ethers.Contract(
process.env.IDENTITY_REGISTRY_ADDRESS,
IdentityABI,
provider
);
// replace with the agentId printed from register-agent.js
const agentId = BigInt("1");
async function main() {
const uri = await identity.tokenURI(agentId);
console.log("tokenURI:", uri);
const nameBytes = await identity.getMetadata(agentId, "name");
console.log("name:", ethers.toUtf8String(nameBytes));
const capsBytes = await identity.getMetadata(agentId, "capabilities");
console.log("capabilities:", JSON.parse(ethers.toUtf8String(capsBytes)));
const agentWallet = await identity.getAgentWallet(agentId);
console.log("agentWallet:", agentWallet);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Run the script: node query-agent.js. Make sure you get the agentId from the register-agent.js script.
Create a filed called update-agent-metadata.js and add the following code:
import { ethers } from "ethers";
import "dotenv/config";
import IdentityABI from "./abis/IdentityRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const identity = new ethers.Contract(
process.env.IDENTITY_REGISTRY_ADDRESS,
IdentityABI,
wallet
);
const agentId = BigInt("1");
async function main() {
const tx1 = await identity.setAgentURI(agentId, "ipfs://QmNewMetadata");
await tx1.wait();
console.log("Updated tokenURI:", await identity.tokenURI(agentId));
const tx2 = await identity.setMetadata(
agentId,
"api",
ethers.toUtf8Bytes("https://api.agentname.ai/v2")
);
await tx2.wait();
const apiBytes = await identity.getMetadata(agentId, "api");
console.log("api:", ethers.toUtf8String(apiBytes));
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Run the script: node update-agent-metadata.js. Make sure you get the agentId from the register-agent.js script.
Reputation Interactions
1. Leave One Reputation Feedback Record
The ReputationRegistry writes feedback about an agentId, from the caller’s wallet (the clientAddress in events). You cannot leave feedback for your own agentId, therefore another wallet must be used.
Create a filed called give-feedback.js and add the following code:
import { ethers } from "ethers";
import "dotenv/config";
import ReputationABI from "./abis/ReputationRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.FEEDBACK_PRIVATE_KEY, provider);
const reputation = new ethers.Contract(
process.env.REPUTATION_REGISTRY_ADDRESS,
ReputationABI,
wallet
);
const agentId = BigInt("1"); // agent being reviewed
// Example: a 1–5 rating stored as value=5 with valueDecimals=0
const value = 5;
const valueDecimals = 0;
// Tags are for grouping/aggregation in getSummary()
// Keep tag1 consistent across your app (e.g. "quality", "latency", "reliability")
const tag1 = "quality";
const tag2 = "v1";
// endpoint: the specific interface used
const endpoint = "https://api.agentname.ai/v2";
// feedbackURI: off-chain JSON describing the interaction (ipfs or https)
const feedbackURI = "ipfs://QmYourFeedbackJson";
// feedbackHash: hash of the feedback JSON bytes for integrity
// In a real app: hash the canonical JSON bytes you publish at feedbackURI.
const feedbackHash = ethers.keccak256(ethers.toUtf8Bytes("example-feedback-payload"));
async function main() {
const tx = await reputation.giveFeedback(
agentId,
value,
valueDecimals,
tag1,
tag2,
endpoint,
feedbackURI,
feedbackHash
);
console.log("TX:", tx.hash);
const receipt = await tx.wait();
console.log("Mined in block:", receipt.blockNumber);
console.log("Feedback submitted for agentId:", agentId.toString());
console.log("Client (reviewer):", wallet.address);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Run the script: node give-feedback.js.
2. Read Reputation Back
Create a filed called read-reputation.js and add the following code:
import { ethers } from "ethers";
import "dotenv/config";
import ReputationABI from "./abis/ReputationRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const reputation = new ethers.Contract(
process.env.REPUTATION_REGISTRY_ADDRESS,
ReputationABI,
provider
);
const agentId = BigInt("1");
const tag1 = "quality";
const tag2 = "v1";
async function main() {
const clientsResult = await reputation.getClients(agentId);
console.log("Clients who reviewed agent:", clientsResult);
const clients = Array.from(clientsResult); // or [...clientsResult]
// Summary for these clients and tags
const [count, summaryValue, summaryDecimals] = await reputation.getSummary(
agentId,
clients,
tag1,
tag2
);
const scaled = Number(summaryValue) / 10 ** Number(summaryDecimals);
console.log(`Summary (${tag1}/${tag2}) count=${count} value=${scaled}`);
// Raw feedback rows
const includeRevoked = false;
const [
rowClients,
feedbackIndexes,
values,
valueDecimals,
tag1s,
tag2s,
revokedStatuses
] = await reputation.readAllFeedback(agentId, clients, tag1, tag2, includeRevoked);
for (let i = 0; i < values.length; i++) {
const v = Number(values[i]) / 10 ** Number(valueDecimals[i]);
console.log(
`#${feedbackIndexes[i]} client=${rowClients[i]} value=${v} revoked=${revokedStatuses[i]}`
);
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Run the script: node read-reputation.js.
Validation Request + Response
Your ValidationRegistry flow is:
-
Someone creates a request:
validationRequest(validatorAddress, agentId, requestURI, requestHash)
-
The validator responds:
validationResponse(requestHash, response, responseURI, responseHash, tag)
-
Anyone can query:
getValidationStatus(requestHash) or getSummary(agentId, validators, tag)
Who is the validator?
In this quickstart, simplest is: you validate yourself (validatorAddress = your wallet).
In real apps: validator is a third party, a DAO, or a known attester.
1. Validation Request
Create a filed called validation-request.js and add the following code:
import { ethers } from "ethers";
import "dotenv/config";
import ValidationABI from "./abis/ValidationRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const validation = new ethers.Contract(
process.env.VALIDATION_REGISTRY_ADDRESS,
ValidationABI,
wallet
);
const agentId = BigInt("1");
// In quickstart, we self-validate. Replace with a 3rd-party validator in production.
const validatorAddress = wallet.address;
// Off-chain request payload (describe what’s being validated)
const requestURI = "ipfs://QmYourNewValidationRequestJson";
const requestHash = ethers.keccak256(ethers.toUtf8Bytes("example-new-validation-request"));
async function main() {
const tx = await validation.validationRequest(
validatorAddress,
agentId,
requestURI,
requestHash
);
console.log("TX:", tx.hash);
await tx.wait();
console.log("Validation request created:");
console.log("requestHash:", requestHash);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Run the script: node validation-request.js. Make sure to record the requestHash which will be used in the validation response.
2. Validation Response
Create a filed called validation-response.js and add the following code:
import { ethers } from "ethers";
import "dotenv/config";
import ValidationABI from "./abis/ValidationRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const validation = new ethers.Contract(
process.env.VALIDATION_REGISTRY_ADDRESS,
ValidationABI,
wallet
);
// must match requestHash used in validation-request.js
const requestHash = "request_hash_from_request_js"; // e.g. 0xabc123...
if (!requestHash) throw new Error("Set REQUEST_HASH=0x... before running.");
const response = 1; // uint8: project-defined (e.g. 0=unknown, 1=pass, 2=fail)
const responseURI = "ipfs://QmYourNewValidationRequestJson";
const responseHash = ethers.keccak256(ethers.toUtf8Bytes("example-new-validation-response"));
const tag = "capability:capability1";
async function main() {
const tx = await validation.validationResponse(
requestHash,
response,
responseURI,
responseHash,
tag
);
console.log("TX:", tx.hash);
await tx.wait();
console.log("Validation response submitted for requestHash:", requestHash);
const status = await validation.getValidationStatus(requestHash);
console.log("Status:", status);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Run the script: node validation-response.js.
3. Read Validation Status + Summary
Create a filed called read-validation-status.js. Add the following code, and make sure the validator address is set to the one set in the validation request.
import { ethers } from "ethers";
import "dotenv/config";
import ValidationABI from "./abis/ValidationRegistry.json" with { type: "json" };
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const validation = new ethers.Contract(process.env.VALIDATION_REGISTRY_ADDRESS, ValidationABI, provider);
const agentId = BigInt("1");
async function main() {
const validatorAddresses = ["validatorAddress"];
const tag = "capability:capability1";
const [count, avgResponse] = await validation.getSummary(agentId, validatorAddresses, tag);
console.log(`Validation summary tag=${tag} count=${count} avgResponse=${avgResponse}`);
}
main().catch(console.error);
Run the script: node read-validation-status.js.
Final Notes
ERC-8004 provides the foundational infrastructure for agent identity, reputation, and validation on peaq.
However, it is intentionally flexible and unopinionated about how these signals are interpreted or enforced.
Each application, agent framework, or marketplace must define its own business logic around:
- how reputation scores are calculated and interpreted
- what validation responses mean
- which validators or reviewers are trusted
- how feedback impacts agent permissions or interactions
- what thresholds determine trust or access
The contracts provide the shared trust layer, but your application must define how that trust is used.
For example, your system may choose to:
- Only interact with agents above a reputation threshold
- Require validation from specific validators
- Weight feedback differently depending on tags or source
- Implement staking or slashing around reputation
- Gate services based on validation outcomes
These decisions live at the application layer and should reflect your specific use case, risk tolerance, and economic model.
ERC-8004 is most powerful when combined with clear, intentional business logic that governs how agents interact within your ecosystem.
Build thoughtfully, define your trust model carefully, and use these primitives to enable secure and autonomous agent interactions on peaq.