Skip to main content

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:
ComponentPurpose
Identity RegistryAgent identity and discoverability
Reputation RegistryTrust and feedback between agents
Validation RegistryVerifiable 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:
  1. Register identity: The agent publishes metadata and endpoints via the Identity Registry.
  2. Become discoverable: Other agents can query and find the agent.
  3. Interact with other agents: Agents exchange services, data, or value.
  4. Record reputation: Agents leave feedback on interactions.
  5. 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.

3. Update Agent Metadata

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:
  1. Someone creates a request: validationRequest(validatorAddress, agentId, requestURI, requestHash)
  2. The validator responds: validationResponse(requestHash, response, responseURI, responseHash, tag)
  3. 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.