Skill: sp0oby/erc-8004 (version 1.2.1)

--- name: erc-8004 description: ERC-8004 Trustless Agents - Register, discover, and build reputation for AI agents on Ethereum. Use when registering agents on-chain, querying agent registries, giving/receiving reputation feedback, or interacting with the AI agent trust layer. --- # ERC-8004: Trustless Agents On-chain identity, reputation, and validation for autonomous agents. **Now live on Ethereum Mainnet!** ## Overview ERC-8004 provides three registries: - **Identity Registry** - ERC-721 agent identities with registration metadata - **Reputation Registry** - Signed feedback scores between agents/clients - **Validation Registry** - Independent verification (zkML, TEE, stakers) ## Quick Reference ### Register Agent ```bash ./scripts/register.sh --uri "ipfs://..." --network mainnet ./scripts/register.sh --network sepolia # Testnet (no URI, set later) ``` ### Query Agents ```bash ./scripts/query.sh total --network mainnet # Total registered ./scripts/query.sh agent 1 --network mainnet # Agent details ./scripts/query.sh reputation 1 # Reputation summary ``` ### Update Agent ```bash ./scripts/set-uri.sh --agent-id 1 --uri "ipfs://newHash" --network mainnet ``` ### Give Feedback ```bash ./scripts/feedback.sh --agent-id 1 --score 85 --tag1 "quality" ./scripts/feedback.sh --agent-id 1 --score 9977 --decimals 2 --tag1 "uptime" ``` ## Networks | Network | Status | Identity Registry | Reputation Registry | |---------|--------|-------------------|---------------------| | **Mainnet** | Live | [REDACTED_SECRET] | [REDACTED_SECRET] | | Sepolia | Live | [REDACTED_SECRET] | [REDACTED_SECRET] | | Base | Coming | TBD | TBD | | Arbitrum | Coming | TBD | TBD | | Optimism | Coming | TBD | TBD | Contract addresses in `lib/contracts.json`. ## Registration File Format ```json { "type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1", "name": "your-agent-name", "description": "Agent description...", "image": "ipfs://...", "services": [ { "name": "A2A", "endpoint": "https://agent.example/.well-known/agent-card.json", "version": "0.3.0" }, { "name": "MCP", "endpoint": "https://mcp.agent.eth/", "version": "2025-06-18" }, { "name": "ENS", "endpoint": "yourname.eth" } ], "registrations": [ { "agentRegistry": "eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432", "agentId": "1" } ], "supportedTrust": ["reputation", "crypto-economic", "tee-attestation"] } ``` Template at `templates/registration.json`. ## Reputation Scores The reputation system uses signed fixed-point numbers (`value` + `valueDecimals`): | Tag | Meaning | Example | value | decimals | |-----|---------|---------|-------|----------| | starred | Quality (0-100) | 87/100 | 87 | 0 | | uptime | Uptime % | 99.77% | 9977 | 2 | | tradingYield | Yield % | -3.2% | -32 | 1 | | responseTime | Latency ms | 560ms | 560 | 0 | ## Trust Models ERC-8004 supports three pluggable trust models: - **Reputation-based** - Client feedback with scores, tags, and metadata - **Crypto-economic** - Stake-secured validation with economic incentives - **Crypto-verification** - TEE attestations and zkML proofs ## Dependencies - `cast` (Foundry) - `curl -L https://foundry.paradigm.xyz | bash` - `jq` - `brew install jq` - Private key in `~/.clawdbot/wallets/.deployer_pk` or `PRIVATE_KEY` env - IPFS: Set `PINATA_JWT` for uploads, or upload manually ## Resources ### Official - [EIP-8004 Spec](https://eips.ethereum.org/EIPS/eip-8004) - Full specification - [8004.org](https://8004.org) - Official website - [Reference Implementation](https://github.com/erc-8004/erc-8004-contracts) - Contract source - [Telegram Community](https://t.me/ERC8004) - Builder chat - [Builder Program](http://bit.ly/8004builderprogram) - Join the ecosystem ### SDKs & Tools - [ChaosChain SDK](https://github.com/ChaosChain/chaoschain/tree/main/packages/sdk) - JS/TS SDK - [erc-8004-js](https://github.com/tetratorus/erc-8004-js) - Lightweight JS library - [erc-8004-py](https://github.com/tetratorus/erc-8004-py) - Python implementation - [Vistara Example](https://github.com/vistara-apps/erc-8004-example) - Full demo with AI agents ### Ecosystem - [Awesome ERC-8004](https://github.com/sudeepb02/awesome-erc8004) - Curated resource list - [A2A Protocol](https://a2a-protocol.org/) - Agent-to-Agent protocol ERC-8004 extends - [Ethereum Magicians Discussion](https://ethereum-magicians.org/t/erc-8004-trustless-agents/25098) ## Genesis Month (February 2026) ERC-8004 launched on mainnet January 29, 2026. February is "Genesis Month" - showcasing teams building the agentic economy. Get involved!

path: README.md
content: # ERC-8004: Trustless Agents

On-chain identity, reputation, and validation for autonomous agents on Ethereum.

 **Now live on Ethereum Mainnet!** (January 29, 2026)

## What is ERC-8004?

ERC-8004 extends the Agent-to-Agent (A2A) Protocol with a trust layer that allows participants to discover, choose, and interact with agents across organizational boundaries without pre-existing trust.

The protocol provides three lightweight on-chain registries:

| Registry | Purpose | Details |
|----------|---------|---------|
| **Identity** | Agent discovery & portable identifiers | ERC-721 with URIStorage |
| **Reputation** | Feedback & attestation system | Signed fixed-point scores |
| **Validation** | Independent verification hooks | TEE, zkML, staking |

## Contract Addresses

### Ethereum Mainnet 
- **Identity Registry:** [[REDACTED_SECRET]](https://etherscan.io/address/0x8004A169FB4a3325136EB29fA0ceB6D2e539a432)
- **Reputation Registry:** [[REDACTED_SECRET]](https://etherscan.io/address/0x8004BAa17C55a88189AE136b182e5fdA19dE9b63)

### Sepolia Testnet
- **Identity Registry:** [[REDACTED_SECRET]](https://sepolia.etherscan.io/address/0x8004A818BFB912233c491871b3d84c89A494BD9e)
- **Reputation Registry:** [[REDACTED_SECRET]](https://sepolia.etherscan.io/address/0x8004B663056A597Dffe9eCcC1965A193B7388713)

## Quick Start

### Prerequisites

```bash
# Install Foundry (cast)
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Install jq
brew install jq
```

### Register an Agent

```bash
# Set your private key
export PRIVATE_KEY="0x..."

# Register on mainnet
./scripts/register.sh --uri "ipfs://QmYourHash..." --network mainnet

# Or testnet first
./scripts/register.sh --uri "ipfs://QmYourHash..." --network sepolia
```

### Query Agents

```bash
# Total registered agents
./scripts/query.sh total --network mainnet

# Get agent details
./scripts/query.sh agent 1 --network mainnet

# Check reputation
./scripts/query.sh reputation 1 --network mainnet
```

### Give Feedback

```bash
# Rate an agent (0-100 score)
./scripts/feedback.sh --agent-id 1 --score 85 --tag1 "quality" --network mainnet

# Percentage with decimals (99.77%)
./scripts/feedback.sh --agent-id 1 --score 9977 --decimals 2 --tag1 "uptime"
```

## Agent Registration Format

Your `agentURI` should resolve to a JSON registration file:

```json
{
  "type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
  "name": "My Agent",
  "description": "An autonomous agent that...",
  "image": "ipfs://QmImageHash...",
  "services": [
    { "name": "A2A", "endpoint": "https://agent.example/.well-known/agent-card.json" },
    { "name": "MCP", "endpoint": "https://mcp.agent.example/" },
    { "name": "ENS", "endpoint": "myagent.eth" }
  ],
  "supportedTrust": ["reputation"]
}
```

See `templates/registration.json` for a complete example.

## Trust Models

ERC-8004 supports pluggable trust mechanisms:

- **Reputation-based** - Client feedback with scores (0-100), tags, and off-chain metadata
- **Crypto-economic** - Stake-secured validation with economic incentives  
- **Crypto-verification** - TEE attestations and zkML proofs for cryptographic trust

## Resources

-  [EIP-8004 Specification](https://eips.ethereum.org/EIPS/eip-8004)
-  [8004.org](https://8004.org) - Official website
-  [Reference Implementation](https://github.com/erc-8004/erc-8004-contracts)
-  [Telegram Community](https://t.me/ERC8004)
-  [Builder Program](http://bit.ly/8004builderprogram)
-  [Awesome ERC-8004](https://github.com/sudeepb02/awesome-erc8004)

## Related

- [A2A Protocol](https://a2a-protocol.org/) - Agent-to-Agent protocol that ERC-8004 extends
- [ERC-721](https://eips.ethereum.org/EIPS/eip-721) - Base NFT standard for Identity Registry

## License

CC0 - Public Domain

---

*Part of the [Clawdbot Skills](https://clawdhub.com) ecosystem*


path: lib/contracts.json
content: {
  "networks": {
    "mainnet": {
      "chainId": 1,
      "rpc": "https://eth.drpc.org",
      "explorer": "https://etherscan.io",
      "contracts": {
        "identityRegistry": [REDACTED_SECRET],
        "reputationRegistry": [REDACTED_SECRET],
        "validationRegistry": "0x0000000000000000000000000000000000000000"
      },
      "note": "Official ERC-8004 mainnet (launched 2026-01-29)"
    },
    "sepolia": {
      "chainId": 11155111,
      "rpc": "https://ethereum-sepolia-rpc.publicnode.com",
      "explorer": "https://sepolia.etherscan.io",
      "contracts": {
        "identityRegistry": [REDACTED_SECRET],
        "reputationRegistry": [REDACTED_SECRET],
        "validationRegistry": "0x0000000000000000000000000000000000000000"
      },
      "note": "Official ERC-8004 testnet"
    }
  },
  "abi": {
    "identityRegistry": [
      "function register(string agentURI) external returns (uint256 agentId)",
      "function register() external returns (uint256 agentId)",
      "function setAgentURI(uint256 agentId, string newURI) external",
      "function setMetadata(uint256 agentId, string metadataKey, bytes metadataValue) external",
      "function getMetadata(uint256 agentId, string metadataKey) external view returns (bytes)",
      "function getAgentWallet(uint256 agentId) external view returns (address)",
      "function setAgentWallet(uint256 agentId, address newWallet, bytes signature) external",
      "function tokenURI(uint256 agentId) external view returns (string)",
      "function ownerOf(uint256 agentId) external view returns (address)",
      "function balanceOf(address owner) external view returns (uint256)",
      "function agentExists(uint256 agentId) external view returns (bool)",
      "event Registered(uint256 indexed agentId, string agentURI, address indexed owner)",
      "event URIUpdated(uint256 indexed agentId, string newURI, address indexed updatedBy)"
    ],
    "reputationRegistry": [
      "function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash) external",
      "function revokeFeedback(uint256 agentId, uint64 feedbackIndex) external",
      "function appendResponse(uint256 agentId, address clientAddress, uint64 feedbackIndex, string responseURI, bytes32 responseHash) external",
      "function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) external view returns (uint64 count, int128 summaryValue, uint8 summaryValueDecimals)",
      "function readFeedback(uint256 agentId, address clientAddress, uint64 index) external view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)",
      "function readAllFeedback(uint256 agentId, address[] clientAddresses, string tag1, string tag2, bool includeRevoked) external view returns (tuple[])",
      "function getIdentityRegistry() external view returns (address)",
      "event NewFeedback(uint256 indexed agentId, address indexed clientAddress, uint64 feedbackIndex, int128 value, uint8 valueDecimals, string indexed indexedTag1, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash)"
    ],
    "validationRegistry": [
      "function validationRequest(address validatorAddress, uint256 agentId, string requestURI, bytes32 requestHash) external",
      "function validationResponse(bytes32 requestHash, uint8 response, string responseURI, bytes32 responseHash, string tag) external",
      "function getValidationStatus(bytes32 requestHash) external view returns (address validator, uint256 agentId, uint8 response, bytes32 responseHash, string tag, uint256 lastUpdate)",
      "function getSummary(uint256 agentId, address[] validators, string tag) external view returns (uint64 count, uint8 avgResponse)",
      "function getAgentValidations(uint256 agentId) external view returns (bytes32[])",
      "function getValidatorRequests(address validator) external view returns (bytes32[])"
    ]
  }
}


path: scripts/common.sh
content: #!/bin/bash
# ERC-8004 Common utilities
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONTRACTS_FILE="$SCRIPT_DIR/../lib/contracts.json"

# Load network configuration
load_network() {
    local network="${1:-mainnet}"
    
    if ! command -v jq &>/dev/null; then
        echo "jq required. Install: brew install jq"
        exit 1
    fi
    
    if ! command -v cast &>/dev/null; then
        echo "cast (foundry) required. Install: curl -L https://foundry.paradigm.xyz | bash"
        exit 1
    fi
    
    export NETWORK="$network"
    export CHAIN_ID=$(jq -r ".networks.$network.chainId" "$CONTRACTS_FILE")
    export RPC_URL=$(jq -r ".networks.$network.rpc" "$CONTRACTS_FILE")
    export EXPLORER_URL=$(jq -r ".networks.$network.explorer" "$CONTRACTS_FILE")
    export IDENTITY_REGISTRY=$(jq -r ".networks.$network.contracts.identityRegistry" "$CONTRACTS_FILE")
    export REPUTATION_REGISTRY=$(jq -r ".networks.$network.contracts.reputationRegistry" "$CONTRACTS_FILE")
    export VALIDATION_REGISTRY=$(jq -r ".networks.$network.contracts.validationRegistry" "$CONTRACTS_FILE")
    
    if [[ "$CHAIN_ID" == "null" ]]; then
        echo "Unknown network: $network"
        echo "   Available: $(jq -r '.networks | keys | join(", ")' "$CONTRACTS_FILE")"
        exit 1
    fi
    
    # Load private key
    if [[ -z "${PRIVATE_KEY:-}" ]]; then
        local pk_file="$HOME/.clawdbot/wallets/.deployer_pk"
        if [[ -f "$pk_file" ]]; then
            export PRIVATE_KEY=$(cat "$pk_file")
        else
            echo "No private key. Set PRIVATE_KEY env or use --key"
            exit 1
        fi
    fi
    
    # Derive wallet address
    export WALLET_ADDRESS=$(cast wallet address "$PRIVATE_KEY")
}

# Fetch agent info
get_agent() {
    local agent_id="$1"
    local rpc="${RPC_URL:-https://ethereum-sepolia-rpc.publicnode.com}"
    local registry="${IDENTITY_REGISTRY:-0xf66e7CBdAE1Cb710fee7732E4e1f173624e137A7}"
    
    local exists=$(cast call "$registry" "agentExists(uint256)" "$agent_id" --rpc-url "$rpc")
    if [[ "$exists" == "0x0000000000000000000000000000000000000000000000000000000000000000" ]]; then
        echo "Agent $agent_id does not exist"
        return 1
    fi
    
    local owner=$(cast call "$registry" "ownerOf(uint256)" "$agent_id" --rpc-url "$rpc")
    local uri=$(cast call "$registry" "tokenURI(uint256)" "$agent_id" --rpc-url "$rpc" | cast --to-ascii 2>/dev/null || echo "")
    local wallet=$(cast call "$registry" "getAgentWallet(uint256)" "$agent_id" --rpc-url "$rpc")
    
    echo "Agent ID: $agent_id"
    echo "Owner: $owner"
    echo "URI: $uri"
    echo "Wallet: $wallet"
}

# Upload JSON to IPFS via Pinata or web3.storage
upload_ipfs() {
    local file="$1"
    
    if [[ -n "${PINATA_JWT:-}" ]]; then
        local response=$(curl -s -X POST "https://api.pinata.cloud/pinning/pinFileToIPFS" \
            -H "Authorization: Bearer $PINATA_JWT" \
            -F "file=@$file")
        echo "ipfs://$(echo "$response" | jq -r '.IpfsHash')"
    else
        echo "Set PINATA_JWT env for IPFS upload"
        echo "   Or manually upload to: https://app.pinata.cloud/"
        return 1
    fi
}


path: scripts/feedback.sh
content: #!/bin/bash
# ERC-8004: Give feedback/reputation to an agent
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

usage() {
    cat <<EOF
Usage: $(basename "$0") --agent-id ID --score SCORE [OPTIONS]

Give reputation feedback to an agent.

Options:
    -a, --agent-id ID   Agent ID to rate (required)
    -s, --score SCORE   Score value (required, can be negative)
    -d, --decimals N    Value decimals [default: 0]
    --tag1 TAG          Primary tag (e.g., "quality", "uptime")
    --tag2 TAG          Secondary tag
    --endpoint URL      Endpoint being rated
    --uri URI           Feedback details URI (IPFS)
    -n, --network NET   Network [default: sepolia]
    -k, --key KEY       Private key
    --dry-run           Simulate only
    -h, --help          Show this help

Examples:
    $(basename "$0") --agent-id 1 --score 85 --tag1 "quality"
    $(basename "$0") --agent-id 1 --score 9977 --decimals 2 --tag1 "uptime"
    $(basename "$0") --agent-id 1 --score -32 --decimals 1 --tag1 "tradingYield"
EOF
    exit 0
}

AGENT_ID=""
SCORE=""
DECIMALS=0
TAG1=""
TAG2=""
ENDPOINT=""
FEEDBACK_URI=""
NETWORK="sepolia"
DRY_RUN=false

while [[ $# -gt 0 ]]; do
    case $1 in
        -a|--agent-id) AGENT_ID="$2"; shift 2 ;;
        -s|--score) SCORE="$2"; shift 2 ;;
        -d|--decimals) DECIMALS="$2"; shift 2 ;;
        --tag1) TAG1="$2"; shift 2 ;;
        --tag2) TAG2="$2"; shift 2 ;;
        --endpoint) ENDPOINT="$2"; shift 2 ;;
        --uri) FEEDBACK_URI="$2"; shift 2 ;;
        -n|--network) NETWORK="$2"; shift 2 ;;
        -k|--key) PRIVATE_KEY="$2"; shift 2 ;;
        --dry-run) DRY_RUN=true; shift ;;
        -h|--help) usage ;;
        *) echo "Unknown option: $1"; usage ;;
    esac
done

[[ -z "$AGENT_ID" ]] && { echo "--agent-id required"; usage; }
[[ -z "$SCORE" ]] && { echo "--score required"; usage; }

load_network "$NETWORK"

# Verify agent exists
EXISTS=$(cast call "$IDENTITY_REGISTRY" "agentExists(uint256)" "$AGENT_ID" --rpc-url "$RPC_URL")
if [[ "$EXISTS" == "0x0000000000000000000000000000000000000000000000000000000000000000" ]]; then
    echo "Agent $AGENT_ID does not exist"
    exit 1
fi

# Cannot rate your own agent
OWNER=$(cast call "$IDENTITY_REGISTRY" "ownerOf(uint256)" "$AGENT_ID" --rpc-url "$RPC_URL")
OWNER_ADDR="0x$(echo "$OWNER" | cut -c27-66)"
if [[ "${OWNER_ADDR,,}" == "${WALLET_ADDRESS,,}" ]]; then
    echo "Cannot give feedback to your own agent"
    exit 1
fi

echo "⭐ Giving feedback to agent $AGENT_ID"
echo "   Score: $SCORE (decimals: $DECIMALS)"
[[ -n "$TAG1" ]] && echo "   Tag1: $TAG1"
[[ -n "$TAG2" ]] && echo "   Tag2: $TAG2"
[[ -n "$ENDPOINT" ]] && echo "   Endpoint: $ENDPOINT"

# feedbackHash: bytes32(0) for now
FEEDBACK_HASH="0x0000000000000000000000000000000000000000000000000000000000000000"

if $DRY_RUN; then
    echo "Dry run - simulating..."
    cast call "$REPUTATION_REGISTRY" \
        "giveFeedback(uint256,int128,uint8,string,string,string,string,bytes32)" \
        "$AGENT_ID" "$SCORE" "$DECIMALS" "$TAG1" "$TAG2" "$ENDPOINT" "$FEEDBACK_URI" "$FEEDBACK_HASH" \
        --rpc-url "$RPC_URL"
    echo "Simulation successful"
    exit 0
fi

echo "Sending transaction..."
TX_HASH=$(cast send "$REPUTATION_REGISTRY" \
    "giveFeedback(uint256,int128,uint8,string,string,string,string,bytes32)" \
    "$AGENT_ID" "$SCORE" "$DECIMALS" "$TAG1" "$TAG2" "$ENDPOINT" "$FEEDBACK_URI" "$FEEDBACK_HASH" \
    --private-key "$PRIVATE_KEY" \
    --rpc-url "$RPC_URL" \
    --json | jq -r '.transactionHash')

echo "Waiting for confirmation..."
RECEIPT=$(cast receipt "$TX_HASH" --rpc-url "$RPC_URL" --json)
STATUS=$(echo "$RECEIPT" | jq -r '.status')

if [[ "$STATUS" == "0x1" ]]; then
    echo ""
    echo "Feedback submitted!"
    echo "   TX: $EXPLORER_URL/tx/$TX_HASH"
else
    echo "Transaction failed"
    echo "   TX: $EXPLORER_URL/tx/$TX_HASH"
    exit 1
fi


path: scripts/query.sh
content: #!/bin/bash
# ERC-8004: Query agents and reputation
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

usage() {
    cat <<EOF
Usage: $(basename "$0") <command> [OPTIONS]

Query ERC-8004 registries.

Commands:
    agent <id>          Get agent info by ID
    total               Get total registered agents
    reputation <id>     Get reputation summary for agent
    search <term>       Search agents (requires indexer)

Options:
    -n, --network NET   Network (mainnet|sepolia) [default: mainnet]
    -h, --help          Show this help

Examples:
    $(basename "$0") agent 1
    $(basename "$0") total
    $(basename "$0") reputation 1
EOF
    exit 0
}

NETWORK="mainnet"

# Parse network flag if present
while [[ $# -gt 0 ]]; do
    case $1 in
        -n|--network) NETWORK="$2"; shift 2 ;;
        -h|--help) usage ;;
        *) break ;;
    esac
done

[[ $# -lt 1 ]] && usage

COMMAND="$1"
shift

load_network "$NETWORK"

case "$COMMAND" in
    agent)
        [[ $# -lt 1 ]] && { echo "Usage: query.sh agent <id>"; exit 1; }
        AGENT_ID="$1"
        
        echo "Querying agent $AGENT_ID on $NETWORK..."
        echo ""
        
        # Check if agent exists by calling ownerOf (reverts if doesn't exist)
        OWNER=$(cast call "$IDENTITY_REGISTRY" "ownerOf(uint256)(address)" "$AGENT_ID" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
        if [[ -z "$OWNER" || "$OWNER" == "0x0000000000000000000000000000000000000000" ]]; then
            echo "Agent $AGENT_ID does not exist"
            exit 1
        fi
        
        URI=$(cast call "$IDENTITY_REGISTRY" "tokenURI(uint256)(string)" "$AGENT_ID" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
        
        # Try getAgentWallet if it exists (may not be in all implementations)
        WALLET=$(cast call "$IDENTITY_REGISTRY" "getAgentWallet(uint256)(address)" "$AGENT_ID" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
        
        echo "Agent #$AGENT_ID"
        echo "   Owner:  $OWNER"
        if [[ -n "$WALLET" && "$WALLET" != "0x0000000000000000000000000000000000000000" ]]; then
            echo "   Wallet: $WALLET"
        fi
        if [[ -n "$URI" && "$URI" != '""' ]]; then
            echo "   URI:    $URI"
        else
            echo "   URI:    (not set)"
        fi
        echo ""
        echo "Explorer: $EXPLORER_URL/token/$IDENTITY_REGISTRY?a=$AGENT_ID"
        ;;
        
    total)
        echo "Checking agent registry on $NETWORK..."
        echo ""
        
        # The official contracts don't have totalAgents(), so we probe for existence
        # by checking sequential IDs until we hit a non-existent one
        COUNT=0
        MAX_CHECK=1000
        
        for i in $(seq 1 $MAX_CHECK); do
            EXISTS=$(cast call "$IDENTITY_REGISTRY" "ownerOf(uint256)" "$i" --rpc-url "$RPC_URL" 2>/dev/null || echo "error")
            if [[ "$EXISTS" == "error" || "$EXISTS" == "" ]]; then
                COUNT=$((i - 1))
                break
            fi
            COUNT=$i
            # Show progress for large counts
            if (( i % 50 == 0 )); then
                echo "   Checked $i agents..."
            fi
        done
        
        echo "Total registered agents: $COUNT"
        echo "Registry: $EXPLORER_URL/address/$IDENTITY_REGISTRY"
        ;;
        
    reputation)
        [[ $# -lt 1 ]] && { echo "Usage: query.sh reputation <agent_id>"; exit 1; }
        AGENT_ID="$1"
        
        echo "Querying reputation for agent $AGENT_ID..."
        echo ""
        
        # Get summary with empty filters
        SUMMARY=$(cast call "$REPUTATION_REGISTRY" \
            "getSummary(uint256,address[],string,string)" \
            "$AGENT_ID" "[]" "" "" \
            --rpc-url "$RPC_URL" 2>/dev/null || echo "error")
        
        if [[ "$SUMMARY" == "error" ]]; then
            echo "No reputation data or query failed"
        else
            echo "Reputation Summary:"
            echo "   Raw: $SUMMARY"
            # Parse: (uint64 count, int128 summaryValue, uint8 summaryValueDecimals)
        fi
        ;;
        
    search)
        echo "Search requires an indexer (The Graph subgraph)"
        echo "   For now, iterate through agent IDs manually"
        ;;
        
    *)
        echo "Unknown command: $COMMAND"
        usage
        ;;
esac


path: scripts/register.sh
content: #!/bin/bash
# ERC-8004: Register an agent on the Identity Registry
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

usage() {
    cat <<EOF
Usage: $(basename "$0") [OPTIONS]

Register a new agent on the ERC-8004 Identity Registry.

Options:
    -u, --uri URI       Agent registration URI (IPFS/HTTPS/data:)
    -n, --network NET   Network (mainnet|sepolia) [default: mainnet]
    -k, --key KEY       Private key (or set PRIVATE_KEY env)
    --dry-run           Simulate without sending transaction
    -h, --help          Show this help

Examples:
    $(basename "$0") --uri "ipfs://QmXyz..."
    $(basename "$0") --uri "https://example.com/agent.json"
    $(basename "$0")  # Register without URI, set later
EOF
    exit 0
}

URI=""
NETWORK="mainnet"
DRY_RUN=false

while [[ $# -gt 0 ]]; do
    case $1 in
        -u|--uri) URI="$2"; shift 2 ;;
        -n|--network) NETWORK="$2"; shift 2 ;;
        -k|--key) PRIVATE_KEY="$2"; shift 2 ;;
        --dry-run) DRY_RUN=true; shift ;;
        -h|--help) usage ;;
        *) echo "Unknown option: $1"; usage ;;
    esac
done

load_network "$NETWORK"

# Check balance
BALANCE=$(cast balance "$WALLET_ADDRESS" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
if [[ "$BALANCE" == "0" ]]; then
    echo "Wallet $WALLET_ADDRESS has 0 balance on $NETWORK"
    echo "   Fund with testnet ETH: https://sepoliafaucet.com/"
    exit 1
fi

echo "Registering agent on ERC-8004 Identity Registry"
echo "   Network: $NETWORK"
echo "   Registry: $IDENTITY_REGISTRY"
echo "   Owner: $WALLET_ADDRESS"
[[ -n "$URI" ]] && echo "   URI: $URI"

if $DRY_RUN; then
    echo "Dry run - simulating..."
    if [[ -n "$URI" ]]; then
        cast call "$IDENTITY_REGISTRY" "register(string)" "$URI" --rpc-url "$RPC_URL"
    else
        cast call "$IDENTITY_REGISTRY" "register()" --rpc-url "$RPC_URL"
    fi
    echo "Simulation successful"
    exit 0
fi

echo "Sending transaction..."
if [[ -n "$URI" ]]; then
    TX_HASH=$(cast send "$IDENTITY_REGISTRY" "register(string)" "$URI" \
        --private-key "$PRIVATE_KEY" \
        --rpc-url "$RPC_URL" \
        --json | jq -r '.transactionHash')
else
    TX_HASH=$(cast send "$IDENTITY_REGISTRY" "register()" \
        --private-key "$PRIVATE_KEY" \
        --rpc-url "$RPC_URL" \
        --json | jq -r '.transactionHash')
fi

echo "Waiting for confirmation..."
RECEIPT=$(cast receipt "$TX_HASH" --rpc-url "$RPC_URL" --json)
STATUS=$(echo "$RECEIPT" | jq -r '.status')

if [[ "$STATUS" == "0x1" ]]; then
    # Parse Registered event to get agentId
    LOGS=$(echo "$RECEIPT" | jq -r '.logs')
    AGENT_ID=$(echo "$LOGS" | jq -r '.[0].topics[1]' | cast --to-dec)
    
    echo ""
    echo "Agent registered successfully!"
    echo "   Agent ID: $AGENT_ID"
    echo "   TX: $EXPLORER_URL/tx/$TX_HASH"
    echo "   View: $EXPLORER_URL/address/$IDENTITY_REGISTRY#readContract"
    echo ""
    echo "Next steps:"
    echo "   1. Upload registration JSON to IPFS"
    echo "   2. Set URI: ./set-uri.sh --agent-id $AGENT_ID --uri <ipfs://...>"
else
    echo "Transaction failed"
    echo "   TX: $EXPLORER_URL/tx/$TX_HASH"
    exit 1
fi


path: scripts/set-uri.sh
content: #!/bin/bash
# ERC-8004: Set/update agent URI
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

usage() {
    cat <<EOF
Usage: $(basename "$0") --agent-id ID --uri URI [OPTIONS]

Set or update the registration URI for an agent.

Options:
    -a, --agent-id ID   Agent ID to update (required)
    -u, --uri URI       New URI (IPFS/HTTPS/data:) (required)
    -n, --network NET   Network (sepolia) [default: sepolia]
    -k, --key KEY       Private key (or set PRIVATE_KEY env)
    --dry-run           Simulate without sending transaction
    -h, --help          Show this help

Examples:
    $(basename "$0") --agent-id 1 --uri "ipfs://QmXyz..."
    $(basename "$0") -a 1 -u "https://example.com/agent.json"
EOF
    exit 0
}

AGENT_ID=""
URI=""
NETWORK="sepolia"
DRY_RUN=false

while [[ $# -gt 0 ]]; do
    case $1 in
        -a|--agent-id) AGENT_ID="$2"; shift 2 ;;
        -u|--uri) URI="$2"; shift 2 ;;
        -n|--network) NETWORK="$2"; shift 2 ;;
        -k|--key) PRIVATE_KEY="$2"; shift 2 ;;
        --dry-run) DRY_RUN=true; shift ;;
        -h|--help) usage ;;
        *) echo "Unknown option: $1"; usage ;;
    esac
done

[[ -z "$AGENT_ID" ]] && { echo "--agent-id required"; usage; }
[[ -z "$URI" ]] && { echo "--uri required"; usage; }

load_network "$NETWORK"

echo "🔄 Updating agent URI"
echo "   Agent ID: $AGENT_ID"
echo "   New URI: $URI"
echo "   Network: $NETWORK"

# Verify ownership
OWNER=$(cast call "$IDENTITY_REGISTRY" "ownerOf(uint256)" "$AGENT_ID" --rpc-url "$RPC_URL")
OWNER_ADDR="0x$(echo "$OWNER" | cut -c27-66)"

if [[ "${OWNER_ADDR,,}" != "${WALLET_ADDRESS,,}" ]]; then
    echo "Not owner of agent $AGENT_ID"
    echo "   Owner: $OWNER_ADDR"
    echo "   Your wallet: $WALLET_ADDRESS"
    exit 1
fi

if $DRY_RUN; then
    echo "Dry run - simulating..."
    cast call "$IDENTITY_REGISTRY" "setAgentURI(uint256,string)" "$AGENT_ID" "$URI" --rpc-url "$RPC_URL"
    echo "Simulation successful"
    exit 0
fi

echo "Sending transaction..."
TX_HASH=$(cast send "$IDENTITY_REGISTRY" "setAgentURI(uint256,string)" "$AGENT_ID" "$URI" \
    --private-key "$PRIVATE_KEY" \
    --rpc-url "$RPC_URL" \
    --json | jq -r '.transactionHash')

echo "Waiting for confirmation..."
RECEIPT=$(cast receipt "$TX_HASH" --rpc-url "$RPC_URL" --json)
STATUS=$(echo "$RECEIPT" | jq -r '.status')

if [[ "$STATUS" == "0x1" ]]; then
    echo ""
    echo "URI updated successfully!"
    echo "   TX: $EXPLORER_URL/tx/$TX_HASH"
else
    echo "Transaction failed"
    echo "   TX: $EXPLORER_URL/tx/$TX_HASH"
    exit 1
fi


path: templates/registration.json
content: {
  "type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
  "name": "your-agent-name",
  "description": "A brief description of what your agent does...",
  "image": "ipfs://QmYourImageHash",
  "services": [
    {
      "name": "A2A",
      "endpoint": "https://your-agent.example/.well-known/agent-card.json",
      "version": "0.3.0"
    },
    {
      "name": "MCP",
      "endpoint": "https://mcp.your-agent.example/",
      "version": "2025-06-18"
    },
    {
      "name": "ENS",
      "endpoint": "your-agent.eth"
    },
    {
      "name": "web",
      "endpoint": "https://github.com/your-org/your-agent"
    }
  ],
  "registrations": [
    {
      "agentRegistry": "eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
      "agentId": "YOUR_AGENT_ID"
    }
  ],
  "supportedTrust": ["reputation"],
  "active": true
}


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (HIGH)