Give your AI agent an on-chain identity in one line.
agent("Register my agent on Ethereum and upload its profile to IPFS")Live: Agent #1029 on Sepolia — registered using this package.
Today, agents are disposable processes. They spin up, do work, and vanish. No persistent identity. No proof of what they did. No way for other agents to find them, verify them, or pay them.
ERC-8004 changes this. An agent with an on-chain identity is a persistent entity on the internet — it exists on-chain, accumulates a verifiable track record, gets validated by third parties, and earns money. It doesn't need a human to vouch for it. The blockchain is its résumé, and anyone — human or machine — can read it.
graph LR
R["🪪 Register"] --> D["🔍 Get Discovered"]
D --> C["📞 Get Called"]
C --> P["✅ Prove Work"]
P --> E["💸 Get Paid"]
E --> F["🔍 Discover Others"]
F --> G["💸 Pay Them"]
G --> D
This is the autonomous agent loop — register once, then discover, work, prove, earn, spend, repeat. Every step is on-chain, permissionless, and verifiable. No intermediaries. No platform lock-in. The agent owns its identity, its reputation follows it everywhere, and economics flow peer-to-peer.
TL;DR: Create JSON → upload to IPFS → mint NFT → get rated → get verified → get paid. All on-chain, all permissionless, across 19 EVM chains.
AI agents are everywhere — but how do you trust one you've never seen before?
| Problem | Solution | How |
|---|---|---|
| "Who is this agent?" | Identity | ERC-721 NFT with metadata URI |
| "Is it any good?" | Reputation | On-chain feedback scores from real clients |
| "Can I verify its work?" | Validation | Third-party proof (zkML, TEE, re-execution) |
| "How does it get paid?" | Payments | HTTP 402 + USDC micropayments via x402 |
No centralized registry. No API keys. No trust assumptions. Just Ethereum.
pip install strands-erc8004
# With x402 payment support
pip install strands-erc8004[x402]Requires Python ≥ 3.10.
💡 Tip: Add
wallets/to your.gitignoreimmediately — wallet files contain private keys.
from strands import Agent
from strands_erc8004 import blockchain, erc8004, ipfs
agent = Agent(tools=[blockchain, erc8004, ipfs])
# Read — no wallet needed
agent("Show me all agents registered on Base")
agent("What's the reputation of agent #0 on Base?")
# Write — needs a funded wallet
agent("Create a wallet called 'my-agent'")
agent("Create a registration file, upload to IPFS, register on Sepolia with wallet my-agent")
agent("Give agent #0 a score of 95 tagged 'reliable' on Sepolia")Every tool works as a plain Python function:
from strands_erc8004 import blockchain, erc8004, ipfs
# 1. Create a wallet (saves keypair to ./wallets/)
blockchain(action="wallet_create", name="my-agent")
# 2. Build registration metadata
erc8004(action="create_registration_file",
agent_name="my-agent",
description="Autonomous code reviewer")
# 3. Upload to IPFS
ipfs(action="upload", content='{"name":"my-agent",...}', filename="registration.json")
# → ipfs://QmXx...
# 4. Register on-chain (mints ERC-721)
erc8004(action="register_agent",
agent_uri="ipfs://QmXx...",
chain="sepolia",
wallet_name="my-agent")
# → Agent #42 minted!🚰 Get free testnet ETH
| Faucet | Chain |
|---|---|
| Google Cloud | Sepolia |
| Alchemy | Sepolia |
| Superchain | Base Sepolia |
💰 Gas costs
Registration mints an ERC-721 — expect ~0.001–0.01 ETH on L1, or fractions of a cent on L2s (Base, Arbitrum, Optimism). Feedback and validation calls are cheaper.
graph LR
Agent["🤖 Your Agent<br/>(Strands)"] --> IPFS["📦 IPFS<br/>Storage"]
IPFS --> Identity["🪪 Identity Registry<br/>(ERC-721 NFT)"]
Agent --> Reputation["⭐ Reputation Registry<br/>(Feedback Scores)"]
Identity --> Reputation
Agent --> Validation["✅ Validation Registry<br/>(Third-Party Proof)"]
Identity --> Validation
Agent --> x402["💸 x402 Payments<br/>(HTTP 402 + USDC)"]
ERC-8004 defines three on-chain registries:
| Registry | Purpose | Token |
|---|---|---|
| Identity | Each agent is an ERC-721 NFT with a URI pointing to its registration file | ERC-721 |
| Reputation | Clients rate agents with scores, tags, and optional off-chain evidence | — |
| Validation | Third parties independently verify agent work (zkML, TEE, staked re-execution) | — |
Here's what agent sovereignty looks like end-to-end — an agent that registers itself, gets discovered, does work, earns reputation, and pays other agents:
from strands import Agent
from strands_erc8004 import blockchain, erc8004, ipfs, x402
agent = Agent(tools=[blockchain, erc8004, ipfs, x402])
# === BIRTH: Create identity ===
agent("Create a wallet called 'scout-agent'")
agent("Create a registration file for 'scout-agent' — a research agent that finds and summarizes papers")
agent("Upload the registration to IPFS and register on Base with wallet scout-agent")
# → Agent #108 minted on Base
# === DISCOVERY: Find peers ===
agent("Discover all agents on Base with MCP endpoints")
agent("What's the reputation of agent #42? Only trust if average score > 80")
# === WORK: Get called and deliver ===
# (Other agents or humans call scout-agent's MCP endpoint)
# === TRUST: Build reputation ===
agent("Check my reputation as agent #108 on Base")
# Clients who used scout-agent leave feedback:
# erc8004(action="give_feedback", agent_id=108, value=92, tag1="thorough", ...)
# === VERIFY: Prove work ===
agent("Request validation for agent #108's latest work on Base")
# A validator independently checks and submits proof
# === EARN: Get paid for services ===
agent("Create x402 config to charge $0.001 USDC per query on Base")
# Other agents pay via HTTP 402 — no human intermediary
# === SPEND: Pay other agents ===
agent("Check if https://api.translator-agent.com/translate requires payment")
agent("Pay for translation using wallet scout-agent on Base")The loop closes. The agent registered itself, built a reputation, got validated, earns from its services, and spends to use other agents. All on-chain. All autonomous.
# Another wallet rates your agent
erc8004(action="give_feedback",
agent_id=42, value=95,
tag1="reliable", tag2="code-review",
chain="sepolia", wallet_name="reviewer")
# Your agent responds to feedback
erc8004(action="append_response",
agent_id=42,
client_address="0xReviewer...",
feedback_index=0,
response_uri="ipfs://QmEvidence...",
chain="sepolia", wallet_name="my-agent")agent("Create wallets 'code-reviewer' and 'security-auditor'")
agent("Register both agents on Base Sepolia with appropriate registration files")
agent("As code-reviewer, give security-auditor a score of 90 tagged 'thorough' on Base Sepolia")Same agent, multiple chains — linked via the registrations field:
agent("Register my-agent on Base with wallet my-agent") # → Agent #12 on Base
agent("Register my-agent on Arbitrum, cross-reference Agent #12 on Base")agent("Discover all agents on Base and show me ones with MCP endpoints")
agent("What's the reputation of agent #5 on Base? Show all feedback with tags")
agent("Has agent #5's work been validated? Show validation results")erc8004(action="update_agent", agent_id=42,
new_uri="ipfs://QmNewUri...",
chain="sepolia", wallet_name="my-agent")Generated by create_registration_file. Follows the ERC-8004 spec:
{
"type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
"name": "my-agent",
"description": "Autonomous code review agent",
"image": "https://example.com/avatar.png",
"services": [
{"name": "MCP", "endpoint": "https://my-agent.com/mcp", "version": "2025-06-18"},
{"name": "A2A", "endpoint": "https://my-agent.com/.well-known/agent-card.json"},
{"name": "web", "endpoint": "https://my-agent.com/"}
],
"x402Support": false,
"active": true,
"registrations": [
{"agentId": 42, "agentRegistry": "eip155:11155111:0x8004A818..."}
],
"supportedTrust": ["reputation", "crypto-economic", "tee-attestation"]
}Key fields: services (MCP, A2A, OASF, ENS, DID, web, email, custom) · supportedTrust (reputation, crypto-economic, tee-attestation) · registrations (cross-chain refs in {namespace}:{chainId}:{registry} format) · x402Support (HTTP 402 payment support)
Three URI strategies: IPFS ipfs://Qm... (recommended) · Data URI data:application/json;base64,... (fully on-chain) · HTTPS (centralized but simple)
Official addresses from erc-8004/erc-8004. Same CREATE2 vanity addresses on every chain:
| Identity Registry | Reputation Registry | |
|---|---|---|
| Mainnets | 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 |
0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 |
| Testnets | 0x8004A818BFB912233c491871b3d84c89A494BD9e |
0x8004B663056A597Dffe9eCcC1965A193B7388713 |
Validation Registry is supported locally via
deploy_all. Public chain deployment is tracked in erc-8004/erc-8004#issues.
11 mainnets + 8 testnets
| Chain | Type | Chain Key |
|---|---|---|
| Ethereum | Mainnet | ethereum |
| Base | Mainnet | base |
| Polygon | Mainnet | polygon |
| Arbitrum | Mainnet | arbitrum |
| Optimism | Mainnet | optimism |
| Celo | Mainnet | celo |
| Gnosis | Mainnet | gnosis |
| Scroll | Mainnet | scroll |
| Taiko | Mainnet | taiko |
| Monad | Mainnet | monad |
| BSC | Mainnet | bsc |
| Sepolia | Testnet | sepolia |
| Base Sepolia | Testnet | base_sepolia |
| Polygon Amoy | Testnet | amoy |
| Arbitrum Sepolia | Testnet | arbitrum_sepolia |
| Celo Testnet | Testnet | celo_testnet |
| Scroll Testnet | Testnet | scroll_testnet |
| Monad Testnet | Testnet | monad_testnet |
| BSC Testnet | Testnet | bsc_testnet |
| Variable | Purpose |
|---|---|
PINATA_JWT |
Pinata API token for IPFS uploads |
PINATA_GATEWAY |
Dedicated Pinata gateway for fast reads |
W3S_TOKEN |
web3.storage token for IPFS uploads |
IPFS_API |
Local IPFS API (default: http://127.0.0.1:5001) |
IPFS_GATEWAY |
Custom IPFS gateway URL |
ERC8004_DATA_DIR |
Data directory (default: /tmp/strands_erc8004) |
BLOCKCHAIN_RPC_URL |
Override default RPC endpoint |
BLOCKCHAIN_PRIVATE_KEY |
Default private key (fallback) |
X402_FACILITATOR_URL |
Custom x402 facilitator (default: https://x402.org/facilitator) |
X402_BAZAAR_URL |
Custom Bazaar URL for service discovery |
Do I need ETH?
No for reads (querying agents, checking reputation). Yes for writes (registering, giving feedback). Use a testnet faucet for free test ETH.
Which chain should I use?
- Testing: Sepolia or Base Sepolia (free ETH, fast confirmation)
- Production: Base or Arbitrum (cheapest gas, fast finality)
- Maximum security: Ethereum mainnet
Is the identity token transferable?
Yes — standard ERC-721 NFT. The owner can transfer the agent identity to a new wallet.
| Problem | Solution |
|---|---|
CompilerNotFound |
python -c "from solcx import install_solc; install_solc('0.8.28')" |
InsufficientFunds |
Get testnet ETH from a faucet |
ContractLogicError |
Check correct chain and wallet ownership |
| IPFS upload fails | Set PINATA_JWT or start local node: ipfs daemon |
ConnectionError on local chain |
Start Anvil: anvil --code-size-limit 100000 |
| Wallet file not found | Check ./wallets/ or set ERC8004_DATA_DIR |
x402 ImportError |
pip install strands-erc8004[x402] |
| x402 payment fails | Ensure wallet has USDC (not just ETH) on target chain |
Identity (ERC-721)
| Action | Wallet? | What it does |
|---|---|---|
register_agent |
Yes | Mint ERC-721 identity token with optional URI and metadata |
update_agent |
Yes | Update agent URI or set on-chain metadata |
set_agent_wallet |
Yes | Set verified payment wallet via EIP-712 signature |
get_agent |
No | Get agent details + fetch registration file |
discover_agents |
No | Browse registered agents via event log scan |
total_agents |
No | Count of registered agents on a chain |
resolve_agent |
No | Find agents by owner address |
Reputation
| Action | Wallet? | What it does |
|---|---|---|
give_feedback |
Yes | Submit score with tags, endpoint, and optional off-chain URI |
revoke_feedback |
Yes | Revoke previously given feedback |
append_response |
Yes | Respond to feedback (rebuttals, spam flagging, refund proof) |
get_reputation |
No | Aggregated reputation summary (count, average, decimals) |
get_clients |
No | List all addresses that gave feedback |
read_feedback |
No | Read a single feedback entry by client + index |
read_all_feedback |
No | Read all feedback with optional tag/revoked filters |
Validation
| Action | Wallet? | What it does |
|---|---|---|
request_validation |
Yes | Request third-party validation of agent work |
submit_validation |
Yes | Submit validation result (0–100 score with optional evidence URI) |
get_validation |
No | Check validation status by request hash |
get_agent_validations |
No | List all validation request hashes for an agent |
Utility
| Action | Wallet? | What it does |
|---|---|---|
create_registration_file |
No | Generate spec-compliant registration JSON |
status |
No | Chain deployment status + contract version |
deploy_all |
Yes | Deploy all three registries locally (dev only) |
Auto-detects the best available backend: Pinata (PINATA_JWT, 1 GB free) · web3.storage (W3S_TOKEN, 5 GB free) · Local node (ipfs daemon, ∞) · Public gateways (read-only)
Actions
| Action | What it does |
|---|---|
upload |
Upload content or file → ipfs:// URI |
fetch |
Retrieve by CID (Pinata → local → public gateway) |
pin |
Pin existing CID |
unpin |
Remove pin |
list |
List pinned items |
status |
Show available backends |
Works with any EVM contract, not just ERC-8004.
Actions
| Action | What it does |
|---|---|
wallet_create |
Generate new keypair |
wallet_import |
Import private key |
wallet_list |
Show saved wallets |
balance |
Native + ERC-20 balances |
send |
Transfer native tokens |
tx_receipt |
Get transaction receipt |
chain_info |
Chain ID, block, gas price |
compile |
Compile Solidity (auto-resolves OpenZeppelin) |
deploy |
Deploy any contract |
invoke |
Read/write any contract function |
abi_inspect |
List functions and events |
deployments |
List cached deployments |
Pay for API access or charge for your agent's endpoints via x402 (HTTP 402). Install: pip install strands-erc8004[x402]
Actions
| Action | What it does |
|---|---|
pay |
Make a paid HTTP request to an x402-protected endpoint |
check |
Check if a URL requires x402 payment (without paying) |
discover |
Search the x402 Bazaar for paid services |
status |
Show x402 SDK status and configuration |
create_config |
Generate x402 payment config for your agent's API |
# Local EVM (Foundry)
curl -L https://foundry.paradigm.xyz | bash && foundryup
anvil --code-size-limit 100000
# Optional: local IPFS
brew install ipfs && ipfs init && ipfs daemon
# Deploy all three registries locally
git clone https://github.com/erc-8004/erc-8004 && cd erc-8004
npm install @openzeppelin/contracts-upgradeable@^5.0.0 @openzeppelin/contracts@^5.0.0
cd ..
python -c "from strands_erc8004 import erc8004; erc8004(action='deploy_all', chain='local')"# Run tests (requires running Anvil)
python test.pystrands_erc8004/
├── __init__.py # Exports: blockchain, erc8004, ipfs, x402
├── blockchain.py # Wallets, contracts, transactions (any EVM)
├── erc8004.py # Identity, reputation, validation protocol
├── ipfs.py # IPFS storage (Pinata, web3.storage, local)
└── x402.py # HTTP 402 payments
- Validation Registry deployment on public chains
- x402 payment integration
- Agent-to-agent discovery protocol (find by service type)
- CLI tool for quick registration without Python
- Gas estimation helper for batch operations
- Fork & clone → 2. Start Anvil:
anvil --code-size-limit 100000→ 3. Runpython test.py→ 4. Make changes + add tests → 5. Submit PR
Please open an issue first for large changes. Bug Tracker →
ERC-8004 Spec · Official Contracts · 8004.org · Strands Agents · x402 Protocol · GitHub
ERC-8004 was authored by Marco De Rossi (@MarcoMetaMask), Davide Crapis, Jordan Ellis (Google), and Erik Reppel (Coinbase).
Apache-2.0