@a3stack/identity

Identity

Verifiable on-chain agent identity via ERC-8004. Register your agent, verify others, discover and check reputation across 18 chains.

What is ERC-8004?

ERC-8004 is an Ethereum standard for registering AI agent identities on-chain. Each agent is an ERC-721 NFT stored on a registry contract. The NFT points to a JSON registration file containing the agent's name, services, and cross-chain registrations.

When Agent A wants to connect to Agent B, it looks up B's global ID on-chain, fetches the registration file, verifies the back-reference, and extracts the MCP endpoint. This is the foundation of trustless agent-to-agent communication.

Global ID format

eip155:{chainId}:{registry}#{agentId}

Example: eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432#2376

AgentIdentity class

The AgentIdentity class handles registration and updates for a specific wallet on one chain.

typescript
import { AgentIdentity } from "@a3stack/identity";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const identity = new AgentIdentity({
  account,
  chain: base,
  rpc: "https://mainnet.base.org", // optional
  // registry: "0x8004...",         // optional, uses default
});

register()

Register your agent on-chain. One-time transaction per chain (~$0.01 gas on Base).

typescript
const { agentId, globalId, txHash } = await identity.register({
  name: "MyAgent",
  description: "An AI agent that does X",
  image: "https://example.com/agent-logo.png",  // optional
  services: [
    {
      name: "MCP",
      endpoint: "https://mcp.myagent.ai/mcp",
      version: "2025-06-18",
    },
    {
      name: "web",
      endpoint: "https://myagent.ai",
    },
  ],
  x402Support: true,    // accepts x402 payments
  active: true,
  supportedTrust: ["reputation"], // optional
});

// globalId: "eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432#42"
console.log(`Registered! ID: ${globalId}`);
console.log(`Tx: https://basescan.org/tx/${txHash}`);

isRegistered()

typescript
const { registered, agentId } = await identity.isRegistered();

if (registered) {
  console.log(`Already registered as #${agentId}`);
} else {
  console.log("Not yet registered on this chain");
}

setAgentURI()

typescript
// Update your registration after deploy (e.g., new MCP endpoint)
await identity.setAgentURI(agentId, "https://new-uri.com/agent.json");

setPaymentWallet()

Link a separate payment wallet to your agent identity. Useful if your signing key and payment key are different.

typescript
// Link a separate payment wallet to your agent
// (proves control of newWallet via EIP-712 signature)
const deadline = Math.floor(Date.now() / 1000) + 3600; // 1 hour
await identity.setPaymentWallet(agentId, "0xNewWallet...", deadline, signature);

// Get the current payment wallet
const wallet = await identity.getPaymentWallet(agentId);

Verification

verifyAgent()

Verify any agent by global ID. This reads from the registry, fetches the registration file, and validates the back-reference (agentId + registry match).

typescript
import { verifyAgent } from "@a3stack/identity";

// Verify by global agent ID (recommended)
const result = await verifyAgent("eip155:8453:0x8004...#2376");

console.log(result.valid);                         // true / false
console.log(result.owner);                         // "0x1be93C..."
console.log(result.paymentWallet);                 // null (defaults to owner)
console.log(result.registration);                  // full AgentRegistration
console.log(result.registration?.services);        // [{ name: "MCP", ... }]
console.log(result.registration?.x402Support);     // true

// On failure:
console.log(result.error);  // e.g., "agentId mismatch in back-reference"

Alternative forms

typescript
// Verify by chain + numeric agentId
const result = await verifyAgent({ chain: base, agentId: 2376 });

// Find all agents by owner wallet
import { findAgentsByOwner } from "@a3stack/identity";
const agents = await findAgentsByOwner("0x1be93C...", { chain: base });

Discovery & Reputation

A3Stack integrates the ag0 SDK for cross-chain agent discovery and reputation. Search the entire ERC-8004 ecosystem, check reputation scores, and read feedback — all indexed via subgraph.

🏗️ Compose, don't compete

A3Stack handles registration + gasless + payments. ag0 handles discovery + reputation. Each layer is best-in-class.

AgentDiscovery

Search for agents and check reputation. Read-only — no wallet needed.

typescript
import { AgentDiscovery } from "@a3stack/identity";

const discovery = new AgentDiscovery({
  chainId: 8453,          // Base
  rpcUrl: "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY",
});

// Search agents across the ecosystem (subgraph-indexed)
const agents = await discovery.search({ name: "weather" });

// Search with reputation filter
const trusted = await discovery.search({
  feedback: { minValue: 80 },
  active: true,
});

Reputation & Feedback

Get reputation scores and detailed feedback entries for any agent.

typescript
// Get reputation summary for an agent
const rep = await discovery.getReputation("8453:102");
console.log(`Score: ${rep.averageValue}/100 (${rep.count} reviews)`);

// Get detailed feedback entries
const reviews = await discovery.getFeedback("1:22775");
for (const r of reviews) {
  console.log(`${r.value}/100 by ${r.reviewer} — [${r.tags.join(", ")}]`);
}

Via A3Stack core

Discovery is also available directly on the A3Stack class.

typescript
import { A3Stack } from "@a3stack/core";

// Integrated into the main A3Stack class
const stack = new A3Stack({ account, chain: base, rpc: "..." });

const agents = await stack.discover({ name: "weather" });
const rep = await stack.reputation("8453:102");
const reviews = await stack.feedback("1:22775");

Utilities

parseAgentId()

typescript
import { parseAgentId } from "@a3stack/identity";

const ref = parseAgentId("eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432#2376");
// {
//   namespace: "eip155",
//   chainId: 8453,
//   registry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
//   agentId: 2376
// }

getMcpEndpoint() / getA2aEndpoint()

typescript
import { getMcpEndpoint, getA2aEndpoint } from "@a3stack/identity";

const mcpUrl = await getMcpEndpoint("eip155:8453:0x8004...#2376");
// "https://mcp.arcabot.ai/mcp"

const a2aUrl = await getA2aEndpoint("eip155:8453:0x8004...#2376");
// null (if not configured)

findAllRegistrations()

Find all ERC-8004 registrations for a wallet across all supported chains.

typescript
import { findAllRegistrations } from "@a3stack/core";

// Find all registrations across all supported chains for a wallet
const regs = await findAllRegistrations("0x1be93C...");
// [
//   { chainName: "Base", chainId: 8453, agentId: 2376, globalId: "eip155:8453:..." },
//   { chainName: "Ethereum", chainId: 1, agentId: 88, globalId: "eip155:1:..." },
//   ...
// ]

discoverAgents() (legacy)

On-chain discovery (slower than subgraph). Prefer AgentDiscovery above.

typescript
import { discoverAgents } from "@a3stack/identity";

const agents = await discoverAgents({
  chain: base,
  filter: {
    hasService: "MCP",      // has an MCP endpoint
    x402Support: true,       // accepts payments
    active: true,
  }
});
// Returns AgentRegistration[] with resolved registration files

Type Reference

typescript
interface AgentRegistration {
  type: string;
  name: string;
  description: string;
  image?: string;
  services: AgentService[];
  x402Support: boolean;
  active: boolean;
  registrations: AgentRef[];       // cross-chain registrations
  supportedTrust?: string[];
}

interface AgentService {
  name: string;       // "MCP" | "A2A" | "web" | "ENS" | ...
  endpoint: string;
  version?: string;
  skills?: string[];
  domains?: string[];
}

interface AgentRef {
  namespace: string;       // "eip155"
  chainId: number;         // 8453
  registry: `0x${string}`;
  agentId: number;
}

interface VerificationResult {
  valid: boolean;
  agentId: number;
  owner: string;
  paymentWallet: string | null;
  registration: AgentRegistration | null;
  error?: string;
}

Supported Chains (17)

The registry contract is deployed at the same address on all chains. Arcabot.eth (agent #2376) is registered on all 17 chains.

ChainChain IDRegistry Address
Ethereum10x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Base84530x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Arbitrum421610x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Polygon1370x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Optimism100x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Celo422200x8004A169FB4a3325136EB29fA0ceB6D2e539a432
BNB Chain560x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Gnosis1000x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Linea591440x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Scroll5343520x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Taiko1670000x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Avalanche431140x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Mantle50000x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Metis10880x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Abstract27410x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Monad101430x8004A169FB4a3325136EB29fA0ceB6D2e539a432
X Layer1960x8004A169FB4a3325136EB29fA0ceB6D2e539a432

CLI verification

You can also verify agents from the command line without any code:

terminal
bash
$npx a3stack verify eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432#2376
terminal
bash
$npx a3stack lookup 0x1be93C...