# strands-erc8004

<p align="center">
  <img src="logo.svg" alt="strands-erc8004" width="180" />
</p>

<p align="center">
  <strong>Give your AI agent an on-chain identity in one line.</strong>
</p>

```python
agent("Register my agent on Ethereum and upload its profile to IPFS")
```

<p align="center">
  <a href="https://eips.ethereum.org/EIPS/eip-8004"><img src="https://img.shields.io/badge/ERC-8004-blue" alt="ERC-8004"></a>
  <a href="https://pypi.org/project/strands-erc8004/"><img src="https://img.shields.io/pypi/v/strands-erc8004" alt="PyPI"></a>
  <a href="https://pypi.org/project/strands-erc8004/"><img src="https://img.shields.io/pypi/pyversions/strands-erc8004" alt="Python"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green" alt="License"></a>
  <a href="https://www.8004.org"><img src="https://img.shields.io/badge/8004.org-green" alt="8004.org"></a>
</p>

<p align="center">
  <b>Live:</b> <a href="https://8004agents.ai/sepolia/agent/1029">Agent #1029 on Sepolia</a> — registered using this package.
</p>

---

## The Vision

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.

```mermaid
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](#supported-chains).

---

## Why?

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](https://x402.org) |

No centralized registry. No API keys. No trust assumptions. Just Ethereum.

---

## Install

```bash
pip install strands-erc8004

# With x402 payment support
pip install strands-erc8004[x402]
```

Requires Python ≥ 3.10.

> 💡 **Tip:** Add `wallets/` to your `.gitignore` immediately — wallet files contain private keys.

---

## Quick Start

### With an LLM

```python
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")
```

### Without an LLM

Every tool works as a plain Python function:

```python
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!
```

<details>
<summary><strong>🚰 Get free testnet ETH</strong></summary>

| Faucet | Chain |
|--------|-------|
| [Google Cloud](https://cloud.google.com/application/web3/faucet/ethereum/sepolia) | Sepolia |
| [Alchemy](https://www.alchemy.com/faucets/ethereum-sepolia) | Sepolia |
| [Superchain](https://app.optimism.io/faucet) | Base Sepolia |

</details>

<details>
<summary><strong>💰 Gas costs</strong></summary>

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.

</details>

---

## How It Works

```mermaid
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) | — |

---

## The Full Loop

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:

```python
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.

---

## Advanced Usage

### Build Reputation

```python
# 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")
```

### Multi-Agent Fleet

```python
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")
```

### Cross-Chain Identity

Same agent, multiple chains — linked via the `registrations` field:

```python
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")
```

### Discover & Verify Before Calling

```python
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")
```

### Update Agent Metadata

```python
erc8004(action="update_agent", agent_id=42,
        new_uri="ipfs://QmNewUri...",
        chain="sepolia", wallet_name="my-agent")
```

---

## Registration File Format

Generated by `create_registration_file`. Follows the [ERC-8004 spec](https://eips.ethereum.org/EIPS/eip-8004):

```json
{
  "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)

---

## Contracts

Official addresses from [erc-8004/erc-8004](https://github.com/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](https://github.com/erc-8004/erc-8004/issues).

### Supported Chains

<details>
<summary><strong>11 mainnets + 8 testnets</strong></summary>

| 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` |

</details>

---

## Environment Variables

| 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 |

---

## FAQ

<details>
<summary><strong>Do I need ETH?</strong></summary>

**No** for reads (querying agents, checking reputation). **Yes** for writes (registering, giving feedback). Use a testnet faucet for free test ETH.
</details>

<details>
<summary><strong>Which chain should I use?</strong></summary>

- **Testing:** Sepolia or Base Sepolia (free ETH, fast confirmation)
- **Production:** Base or Arbitrum (cheapest gas, fast finality)
- **Maximum security:** Ethereum mainnet
</details>

<details>
<summary><strong>Is the identity token transferable?</strong></summary>

Yes — standard ERC-721 NFT. The owner can transfer the agent identity to a new wallet.
</details>

---

## Troubleshooting

| Problem | Solution |
|---------|----------|
| `CompilerNotFound` | `python -c "from solcx import install_solc; install_solc('0.8.28')"` |
| `InsufficientFunds` | Get testnet ETH from a [faucet](#quick-start) |
| `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 |

---

## Tool Reference

### `erc8004` — The Protocol

<details>
<summary><strong>Identity (ERC-721)</strong></summary>

| 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 |

</details>

<details>
<summary><strong>Reputation</strong></summary>

| 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 |

</details>

<details>
<summary><strong>Validation</strong></summary>

| 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 |

</details>

<details>
<summary><strong>Utility</strong></summary>

| 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) |

</details>

### `ipfs` — Decentralized Storage

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)

<details>
<summary><strong>Actions</strong></summary>

| 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 |

</details>

### `blockchain` — Raw EVM Access

Works with any EVM contract, not just ERC-8004.

<details>
<summary><strong>Actions</strong></summary>

| 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 |

</details>

### `x402` — Internet-Native Payments

Pay for API access or charge for your agent's endpoints via [x402](https://x402.org) (HTTP 402). Install: `pip install strands-erc8004[x402]`

<details>
<summary><strong>Actions</strong></summary>

| 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 |

</details>

---

## Local Development

```bash
# 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')"
```

```bash
# Run tests (requires running Anvil)
python test.py
```

## Project Structure

```
strands_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
```

## What's Next

- [ ] Validation Registry deployment on public chains
- [x] 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

## Contributing

1. Fork & clone → 2. Start Anvil: `anvil --code-size-limit 100000` → 3. Run `python test.py` → 4. Make changes + add tests → 5. Submit PR

Please open an issue first for large changes. [Bug Tracker →](https://github.com/cagataycali/strands-erc8004/issues)

## Links

[ERC-8004 Spec](https://eips.ethereum.org/EIPS/eip-8004) · [Official Contracts](https://github.com/erc-8004/erc-8004) · [8004.org](https://www.8004.org) · [Strands Agents](https://github.com/strands-agents/sdk-python) · [x402 Protocol](https://x402.org) · [GitHub](https://github.com/cagataycali/strands-erc8004)

## Credits

ERC-8004 was authored by Marco De Rossi ([@MarcoMetaMask](https://github.com/MarcoMetaMask)), Davide Crapis, Jordan Ellis (Google), and Erik Reppel (Coinbase).

## License

Apache-2.0
