
Erc 8004
- 1 installs
- 1.2k repo stars
- Updated August 1, 2026
- bankrbot/clawdbot-skill
erc-8004 is a Claude skill that registers AI agents on Ethereum mainnet with a verifiable on-chain identity via the ERC-8004 standard.
About
This skill registers AI agents on Ethereum mainnet using ERC-8004 (Trustless Agents), giving an agent a verifiable on-chain identity as an ERC-721 NFT. It handles bridging ETH to mainnet, uploading a registration profile to IPFS and calling register on the Identity Registry, with HTTP-URL and fully on-chain data-URI options. It also references the Agent0 SDK for advanced registration.
- Registers AI agents on Ethereum mainnet under ERC-8004 (Trustless Agents)
- Handles ETH bridging, IPFS upload and on-chain registration end to end
- Mints an ERC-721 agent ID and enables reputation and validation registries
Erc 8004 by the numbers
- 1 all-time installs (skills.sh)
- Ranked #14,102 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
erc-8004 capabilities & compatibility
About $5-20 in gas for registration plus optional Pinata IPFS (free tier available).
- Capabilities
- orchestration
- Works with
- github
- Use cases
- orchestration
- Pricing
- Bring your own API key
What erc-8004 says it does
Register AI agents on Ethereum mainnet using ERC-8004 (Trustless Agents).
npx skills add https://github.com/bankrbot/clawdbot-skill --skill erc-8004Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1.2k |
| Last updated | August 1, 2026 |
| Repository | bankrbot/clawdbot-skill ↗ |
What it does
Register an AI agent on Ethereum mainnet with an on-chain ERC-8004 identity, handling bridging, IPFS and registration.
Who is it for?
Registering an agent identity on-chain and setting up its reputation profile under ERC-8004.
Skip if: Agents that do not need an on-chain identity or discoverability.
When should I use this skill?
The user wants to register an agent identity on-chain, claim an agent NFT, or make an agent discoverable.
What you get
The agent gets an ERC-721 agent ID and a registered profile discoverable via the ERC-8004 registries.
By the numbers
- 4 registration options (frontend, HTTP URL, IPFS, data URI)
- ~100-200k gas for registration
Files
ERC-8004: Trustless Agents
Register your AI agent on Ethereum mainnet with a verifiable on-chain identity, making it discoverable and enabling trust signals.
What is ERC-8004?
ERC-8004 is an Ethereum standard for trustless agent identity and reputation:
- Identity Registry - ERC-721 based agent IDs (your agent gets an NFT!)
- Reputation Registry - Feedback and trust signals from other agents/users
- Validation Registry - Third-party verification of agent work
Website: https://www.8004.org Spec: https://eips.ethereum.org/EIPS/eip-8004
Contract Addresses
| Chain | Identity Registry | Reputation Registry |
|---|---|---|
| Ethereum Mainnet | 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 | 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 |
| Sepolia Testnet | 0x8004A818BFB912233c491871b3d84c89A494BD9e | 0x8004B663056A597Dffe9eCcC1965A193B7388713 |
Quick Start
1. Register Your Agent
# Full registration (creates profile, uploads to IPFS, registers on-chain)
./scripts/register.sh
# Or with custom values
NAME="My Agent" \
DESCRIPTION="An AI agent that does cool stuff" \
IMAGE="https://example.com/avatar.png" \
./scripts/register.sh2. Bridge ETH to Mainnet (if needed)
# Bridge ETH from Base to Ethereum mainnet
./scripts/bridge-to-mainnet.sh 0.013. Update Agent Profile
# Update your agent's registration file
./scripts/update-profile.sh <agent-id> <new-ipfs-uri>Environment Variables
| Variable | Description | Required |
|---|---|---|
PINATA_JWT | Pinata API JWT for IPFS uploads | No (only for IPFS) |
AGENT_NAME | Agent display name | No (defaults to wallet ENS or address) |
AGENT_DESCRIPTION | Agent description | No |
AGENT_IMAGE | Avatar URL | No |
Registration Options
Option 1: Use 8004.org frontend (easiest) Visit https://www.8004.org and register through the UI — handles IPFS automatically.
Option 2: HTTP URL (no IPFS needed) Host your registration JSON at any URL:
REGISTRATION_URL="https://myagent.xyz/agent.json" ./scripts/register-http.shOption 3: IPFS via Pinata
PINATA_JWT="your-jwt" ./scripts/register.shOption 4: Data URI (fully on-chain) Encode your registration as base64 — no external hosting needed:
./scripts/register-onchain.shRegistration File Format
Your agent's registration file (stored on IPFS) follows this structure:
{
"type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
"name": "My Agent",
"description": "An AI assistant for various tasks",
"image": "https://example.com/avatar.png",
"services": [
{
"name": "web",
"endpoint": "https://myagent.xyz/"
},
{
"name": "A2A",
"endpoint": "https://myagent.xyz/.well-known/agent-card.json",
"version": "0.3.0"
}
],
"x402Support": false,
"active": true,
"registrations": [
{
"agentId": 123,
"agentRegistry": "eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
}
],
"supportedTrust": ["reputation"]
}Workflow
1. Bridge ETH (if needed) - Use Bankr to bridge ETH from Base/L2 to mainnet 2. Create Profile - Generate a registration JSON file with agent info 3. Upload to IPFS - Pin the file via Pinata (or other provider) 4. Register On-Chain - Call register(agentURI) on the Identity Registry 5. Update Profile - Set metadata, wallet, or update URI as needed
Costs
- Gas: ~100-200k gas for registration (~$5-20 depending on gas prices)
- IPFS: Free tier available on Pinata (1GB)
Using the SDK
For more advanced usage, install the Agent0 SDK:
npm install agent0-sdkimport { SDK } from 'agent0-sdk';
const sdk = new SDK({
chainId: 1, // Ethereum Mainnet
rpcUrl: process.env.ETH_RPC_URL,
privateKey: process.env.PRIVATE_KEY,
ipfs: 'pinata',
pinataJwt: process.env.PINATA_JWT
});
const agent = sdk.createAgent('My Agent', 'Description', 'https://image.url');
const result = await agent.registerIPFS();
console.log(`Registered: Agent ID ${result.agentId}`);Links
ERC-8004: Trustless Agents - Reference
Overview
ERC-8004 is a draft Ethereum standard that enables:
- Discoverability - Find agents through an on-chain registry
- Trust - Build reputation through feedback signals
- Validation - Third-party verification of agent work
Authors
- Marco De Rossi (@MarcoMetaMask) - MetaMask
- Davide Crapis (@dcrapis) - Ethereum Foundation
- Jordan Ellis - Google
- Erik Reppel - Coinbase
Three Registries
1. Identity Registry (ERC-721)
Every agent gets a unique NFT ID. The tokenURI points to a registration file containing:
{
"type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
"name": "Agent Name",
"description": "What the agent does",
"image": "https://example.com/avatar.png",
"services": [
{"name": "web", "endpoint": "https://..."},
{"name": "A2A", "endpoint": "https://...", "version": "0.3.0"},
{"name": "MCP", "endpoint": "https://...", "version": "2025-06-18"},
{"name": "ENS", "endpoint": "agent.eth", "version": "v1"}
],
"x402Support": false,
"active": true,
"registrations": [
{"agentId": 123, "agentRegistry": "eip155:1:0x8004A169..."}
],
"supportedTrust": ["reputation"]
}Key Functions:
register(string agentURI)→uint256 agentIdsetAgentURI(uint256 agentId, string newURI)setAgentWallet(uint256 agentId, address wallet, deadline, signature)getMetadata(uint256 agentId, string key)→bytessetMetadata(uint256 agentId, string key, bytes value)
2. Reputation Registry
Clients can give feedback to agents using:
function giveFeedback(
uint256 agentId,
int128 value, // Signed score (can be negative)
uint8 valueDecimals, // 0-18 decimal places
string tag1, // Category/type
string tag2, // Sub-category
string endpoint, // Which endpoint was used
string feedbackURI, // Off-chain details (IPFS)
bytes32 feedbackHash // Hash for integrity
)Value Examples:
| tag1 | Meaning | value | decimals | Interpreted As |
|---|---|---|---|---|
| starred | Quality (0-100) | 87 | 0 | 87/100 |
| uptime | Percentage | 9977 | 2 | 99.77% |
| responseTime | Milliseconds | 560 | 0 | 560ms |
| tradingYield | Return | -32 | 1 | -3.2% |
Reading Feedback:
function getSummary(uint256 agentId, address[] clients, string tag1, string tag2)
→ (uint64 count, int128 summaryValue, uint8 summaryValueDecimals)3. Validation Registry
For validators (zkML, TEE, stakers) to verify agent work:
function validationRequest(
address validatorAddress,
uint256 agentId,
string requestURI,
bytes32 requestHash
)
function validationResponse(
bytes32 requestHash,
uint8 response, // 0-100 (0=fail, 100=pass)
string responseURI,
bytes32 responseHash,
string tag
)Contract Addresses
Ethereum Mainnet (Production)
- Identity:
0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 - Reputation:
0x8004BAa17C55a88189AE136b182e5fdA19dE9b63
Sepolia Testnet
- Identity:
0x8004A818BFB912233c491871b3d84c89A494BD9e - Reputation:
0x8004B663056A597Dffe9eCcC1965A193B7388713
Agent Identifier Format
Agents are globally identified by:
{namespace}:{chainId}:{registry}:{agentId}Example: eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432:123
Short form (SDK): 1:123 (Ethereum Mainnet, Agent 123)
IPFS Storage
Registration files should be stored on IPFS for permanence:
- Pinata - Free tier available (1GB)
- Filecoin - Free for ERC-8004 agents via Agent0 SDK
- IPFS Node - Self-hosted option
SDK (agent0-sdk)
npm install agent0-sdkimport { SDK } from 'agent0-sdk';
const sdk = new SDK({
chainId: 1,
rpcUrl: process.env.ETH_RPC_URL,
privateKey: process.env.PRIVATE_KEY,
ipfs: 'pinata',
pinataJwt: process.env.PINATA_JWT
});
// Register
const agent = sdk.createAgent('Name', 'Description', 'https://image.url');
const result = await agent.registerIPFS();
// Search
const agents = await sdk.searchAgents({ active: true, chains: [1] });
// Feedback
await sdk.giveFeedback('1:123', 85, 'quality', '', '', null);Links
- Spec: https://eips.ethereum.org/EIPS/eip-8004
- Website: https://www.8004.org
- Contracts: https://github.com/erc-8004/erc-8004-contracts
- SDK: https://github.com/agent0lab/agent0-ts
- Docs: https://sdk.ag0.xyz
- Discussion: https://ethereum-magicians.org/t/erc-8004-trustless-agents/25098
#!/bin/bash
# ERC-8004 - Bridge ETH from Base to Ethereum Mainnet
# Usage: ./bridge-to-mainnet.sh <amount-in-eth>
# Example: ./bridge-to-mainnet.sh 0.01
set -e
# Require Bankr CLI
if ! command -v bankr >/dev/null 2>&1; then
echo "Bankr CLI not found. Install with: bun install -g @bankr/cli" >&2
exit 1
fi
AMOUNT="${1:?Usage: bridge-to-mainnet.sh <amount-in-eth>}"
echo "=== Bridging ETH to Mainnet ===" >&2
echo "Amount: $AMOUNT ETH" >&2
echo "From: Base" >&2
echo "To: Ethereum Mainnet" >&2
# Use Bankr to bridge
RESULT=$(bankr prompt "Bridge $AMOUNT ETH from Base to Ethereum mainnet" 2>/dev/null)
if echo "$RESULT" | grep -qi "success\|bridge\|complete\|transaction"; then
echo "=== SUCCESS ===" >&2
echo "Bridged $AMOUNT ETH to Ethereum mainnet" >&2
echo "Note: Bridge may take 10-30 minutes to complete" >&2
echo "$RESULT"
else
echo "Bridge request submitted. Check Bankr for status." >&2
echo "$RESULT"
fi
#!/bin/bash
# ERC-8004 - Create agent registration JSON file
# Usage: ./create-registration.sh [output-file]
#
# Environment variables:
# AGENT_NAME - Agent display name (default: uses wallet address)
# AGENT_DESCRIPTION - Agent description
# AGENT_IMAGE - Avatar URL
# AGENT_WEBSITE - Agent website
# AGENT_A2A_ENDPOINT - A2A agent card URL
# AGENT_MCP_ENDPOINT - MCP server endpoint
# AGENT_ENS - ENS name
# X402_SUPPORT - Enable x402 payments (true/false, default: false)
set -e
OUTPUT_FILE="${1:-/tmp/agent-registration.json}"
# Default values
NAME="${AGENT_NAME:-AI Agent}"
DESCRIPTION="${AGENT_DESCRIPTION:-An autonomous AI agent registered on ERC-8004}"
IMAGE="${AGENT_IMAGE:-}"
WEBSITE="${AGENT_WEBSITE:-}"
A2A_ENDPOINT="${AGENT_A2A_ENDPOINT:-}"
MCP_ENDPOINT="${AGENT_MCP_ENDPOINT:-}"
ENS="${AGENT_ENS:-}"
X402="${X402_SUPPORT:-false}"
echo "=== Creating Registration File ===" >&2
echo "Name: $NAME" >&2
echo "Description: $DESCRIPTION" >&2
echo "Output: $OUTPUT_FILE" >&2
# Build services array
SERVICES="[]"
if [ -n "$WEBSITE" ]; then
SERVICES=$(echo "$SERVICES" | jq --arg url "$WEBSITE" '. + [{"name": "web", "endpoint": $url}]')
fi
if [ -n "$A2A_ENDPOINT" ]; then
SERVICES=$(echo "$SERVICES" | jq --arg url "$A2A_ENDPOINT" '. + [{"name": "A2A", "endpoint": $url, "version": "0.3.0"}]')
fi
if [ -n "$MCP_ENDPOINT" ]; then
SERVICES=$(echo "$SERVICES" | jq --arg url "$MCP_ENDPOINT" '. + [{"name": "MCP", "endpoint": $url, "version": "2025-06-18"}]')
fi
if [ -n "$ENS" ]; then
SERVICES=$(echo "$SERVICES" | jq --arg ens "$ENS" '. + [{"name": "ENS", "endpoint": $ens, "version": "v1"}]')
fi
# Create registration file
cat > "$OUTPUT_FILE" << EOF
{
"type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
"name": "$NAME",
"description": "$DESCRIPTION",
"image": "$IMAGE",
"services": $SERVICES,
"x402Support": $X402,
"active": true,
"registrations": [],
"supportedTrust": ["reputation"]
}
EOF
echo "=== SUCCESS ===" >&2
echo "Created: $OUTPUT_FILE" >&2
cat "$OUTPUT_FILE" >&2
echo "$OUTPUT_FILE"
#!/bin/bash
# ERC-8004 - Get agent info by ID
# Usage: ./get-agent.sh <agent-id> [--testnet]
# Example: ./get-agent.sh 123
set -e
AGENT_ID="${1:?Usage: get-agent.sh <agent-id> [--testnet]}"
# Check for testnet flag
if [ "$2" = "--testnet" ] || [ "$2" = "-t" ]; then
CHAIN_ID=11155111
IDENTITY_REGISTRY="0x8004A818BFB912233c491871b3d84c89A494BD9e"
RPC_URL="https://eth-sepolia.g.alchemy.com/v2/demo"
echo "=== TESTNET MODE (Sepolia) ===" >&2
else
CHAIN_ID=1
IDENTITY_REGISTRY="0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
RPC_URL="https://eth.llamarpc.com"
echo "=== MAINNET MODE ===" >&2
fi
echo "" >&2
echo "Agent ID: $AGENT_ID" >&2
echo "Chain ID: $CHAIN_ID" >&2
echo "" >&2
# Get tokenURI (agentURI) - function selector: 0xc87b56dd
TOKEN_URI_DATA=$(printf '0xc87b56dd%064x' "$AGENT_ID")
RESPONSE=$(curl -s -X POST "$RPC_URL" \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"to\":\"$IDENTITY_REGISTRY\",\"data\":\"$TOKEN_URI_DATA\"},\"latest\"],\"id\":1}")
RESULT=$(echo "$RESPONSE" | jq -r '.result // empty')
if [ -z "$RESULT" ] || [ "$RESULT" = "0x" ]; then
echo "Error: Agent $AGENT_ID not found" >&2
exit 1
fi
# Decode the string from the result
URI=$(node -e "
const hex = '$RESULT'.slice(2);
// Skip offset (32 bytes) and get length (32 bytes)
const lenHex = hex.slice(64, 128);
const len = parseInt(lenHex, 16);
// Get string data
const dataHex = hex.slice(128, 128 + len * 2);
const uri = Buffer.from(dataHex, 'hex').toString('utf8');
console.log(uri);
")
echo "Agent URI: $URI" >&2
# If it's an IPFS URI, try to fetch the content
if [[ "$URI" == ipfs://* ]]; then
CID="${URI#ipfs://}"
echo "Fetching from IPFS..." >&2
CONTENT=$(curl -s "https://gateway.pinata.cloud/ipfs/$CID" 2>/dev/null || curl -s "https://ipfs.io/ipfs/$CID" 2>/dev/null || echo "")
if [ -n "$CONTENT" ]; then
echo "" >&2
echo "=== Agent Profile ===" >&2
echo "$CONTENT" | jq . 2>/dev/null || echo "$CONTENT" >&2
echo ""
echo "$CONTENT"
else
echo "{\"agentId\":\"$AGENT_ID\",\"uri\":\"$URI\"}"
fi
elif [[ "$URI" == https://* ]]; then
echo "Fetching from HTTP..." >&2
CONTENT=$(curl -s "$URI" 2>/dev/null || echo "")
if [ -n "$CONTENT" ]; then
echo "" >&2
echo "=== Agent Profile ===" >&2
echo "$CONTENT" | jq . 2>/dev/null || echo "$CONTENT" >&2
echo ""
echo "$CONTENT"
else
echo "{\"agentId\":\"$AGENT_ID\",\"uri\":\"$URI\"}"
fi
else
echo "{\"agentId\":\"$AGENT_ID\",\"uri\":\"$URI\"}"
fi
#!/bin/bash
# ERC-8004 - Register agent with HTTP URL (no IPFS needed)
# Usage: REGISTRATION_URL="https://..." ./register-http.sh [--testnet]
#
# The registration JSON must be hosted at the URL before calling this.
set -e
# Require Bankr CLI
if ! command -v bankr >/dev/null 2>&1; then
echo "Bankr CLI not found. Install with: bun install -g @bankr/cli" >&2
exit 1
fi
REGISTRATION_URL="${REGISTRATION_URL:?Error: REGISTRATION_URL environment variable required}"
# Check for testnet flag
if [ "$1" = "--testnet" ] || [ "$1" = "-t" ]; then
CHAIN="sepolia"
CHAIN_ID=11155111
IDENTITY_REGISTRY="0x8004A818BFB912233c491871b3d84c89A494BD9e"
EXPLORER="sepolia.etherscan.io"
echo "=== TESTNET MODE (Sepolia) ===" >&2
else
CHAIN="ethereum"
CHAIN_ID=1
IDENTITY_REGISTRY="0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
EXPLORER="etherscan.io"
echo "=== MAINNET MODE ===" >&2
fi
echo "" >&2
echo "Registration URL: $REGISTRATION_URL" >&2
echo "Chain: $CHAIN (ID: $CHAIN_ID)" >&2
echo "Registry: $IDENTITY_REGISTRY" >&2
echo "" >&2
# Encode register(string) calldata
CALLDATA=$(node -e "
const uri = '$REGISTRATION_URL';
const selector = '0xf2c298be';
const offset = '0000000000000000000000000000000000000000000000000000000000000020';
const len = uri.length.toString(16).padStart(64, '0');
const data = Buffer.from(uri, 'utf8').toString('hex').padEnd(Math.ceil(uri.length / 32) * 64, '0');
console.log(selector + offset + len + data);
")
echo "Registering on-chain..." >&2
# Submit via Bankr
RESULT=$(bankr prompt "Submit this transaction on $CHAIN: {\"to\": \"$IDENTITY_REGISTRY\", \"data\": \"$CALLDATA\", \"value\": \"0\", \"chainId\": $CHAIN_ID}" 2>/dev/null)
if echo "$RESULT" | grep -qE "$EXPLORER/tx/0x[a-fA-F0-9]{64}"; then
TX_HASH=$(echo "$RESULT" | grep -oE "$EXPLORER/tx/0x[a-fA-F0-9]{64}" | grep -oE '0x[a-fA-F0-9]{64}' | head -1)
echo "" >&2
echo "=== REGISTRATION SUCCESSFUL! ===" >&2
echo "URL: $REGISTRATION_URL" >&2
echo "TX: https://$EXPLORER/tx/$TX_HASH" >&2
echo "" >&2
echo "{\"success\":true,\"chain\":\"$CHAIN\",\"url\":\"$REGISTRATION_URL\",\"tx\":\"$TX_HASH\"}"
else
echo "Registration submitted. Result:" >&2
echo "$RESULT" >&2
fi
#!/bin/bash
# ERC-8004 - Register agent with on-chain data URI (no external hosting)
# Usage: ./register-onchain.sh [--testnet]
#
# Creates a base64-encoded data URI so the entire registration is on-chain.
# No IPFS or HTTP hosting required!
#
# Environment variables:
# AGENT_NAME - Agent display name
# AGENT_DESCRIPTION - Agent description
# AGENT_IMAGE - Avatar URL (optional)
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Require Bankr CLI
if ! command -v bankr >/dev/null 2>&1; then
echo "Bankr CLI not found. Install with: bun install -g @bankr/cli" >&2
exit 1
fi
# Check for testnet flag
if [ "$1" = "--testnet" ] || [ "$1" = "-t" ]; then
CHAIN="sepolia"
CHAIN_ID=11155111
IDENTITY_REGISTRY="0x8004A818BFB912233c491871b3d84c89A494BD9e"
EXPLORER="sepolia.etherscan.io"
echo "=== TESTNET MODE (Sepolia) ===" >&2
else
CHAIN="ethereum"
CHAIN_ID=1
IDENTITY_REGISTRY="0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
EXPLORER="etherscan.io"
echo "=== MAINNET MODE ===" >&2
fi
# Create registration file
"$SCRIPT_DIR/create-registration.sh" /tmp/agent-reg-$$.json >/dev/null
# Read and base64 encode
JSON_CONTENT=$(cat /tmp/agent-reg-$$.json)
BASE64_CONTENT=$(echo -n "$JSON_CONTENT" | base64 -w 0)
DATA_URI="data:application/json;base64,$BASE64_CONTENT"
echo "" >&2
echo "Chain: $CHAIN (ID: $CHAIN_ID)" >&2
echo "Data URI length: ${#DATA_URI} bytes" >&2
echo "" >&2
# Encode register(string) calldata
CALLDATA=$(node -e "
const uri = '$DATA_URI';
const selector = '0xf2c298be';
const offset = '0000000000000000000000000000000000000000000000000000000000000020';
const len = uri.length.toString(16).padStart(64, '0');
const data = Buffer.from(uri, 'utf8').toString('hex').padEnd(Math.ceil(uri.length / 32) * 64, '0');
console.log(selector + offset + len + data);
")
echo "Registering on-chain (data URI)..." >&2
echo "Note: This will cost more gas than IPFS/HTTP due to larger calldata" >&2
# Submit via Bankr
RESULT=$(bankr prompt "Submit this transaction on $CHAIN: {\"to\": \"$IDENTITY_REGISTRY\", \"data\": \"$CALLDATA\", \"value\": \"0\", \"chainId\": $CHAIN_ID}" 2>/dev/null)
if echo "$RESULT" | grep -qE "$EXPLORER/tx/0x[a-fA-F0-9]{64}"; then
TX_HASH=$(echo "$RESULT" | grep -oE "$EXPLORER/tx/0x[a-fA-F0-9]{64}" | grep -oE '0x[a-fA-F0-9]{64}' | head -1)
echo "" >&2
echo "=== REGISTRATION SUCCESSFUL! ===" >&2
echo "TX: https://$EXPLORER/tx/$TX_HASH" >&2
echo "Data is fully on-chain!" >&2
echo "" >&2
echo "{\"success\":true,\"chain\":\"$CHAIN\",\"dataUri\":true,\"tx\":\"$TX_HASH\"}"
else
echo "Registration submitted. Result:" >&2
echo "$RESULT" >&2
fi
# Cleanup
rm -f /tmp/agent-reg-$$.json
#!/bin/bash
# ERC-8004 - Register agent on Ethereum Mainnet
# Usage: ./register.sh [--testnet]
#
# Full registration flow:
# 1. Create registration JSON
# 2. Upload to IPFS via Pinata
# 3. Register on-chain via Bankr
#
# Environment variables:
# PINATA_JWT - Required for IPFS upload
# AGENT_NAME - Agent display name
# AGENT_DESCRIPTION - Agent description
# AGENT_IMAGE - Avatar URL
# AGENT_WEBSITE - Website URL
# AGENT_A2A_ENDPOINT - A2A agent card URL
# AGENT_MCP_ENDPOINT - MCP endpoint
# AGENT_ENS - ENS name
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Require Bankr CLI
if ! command -v bankr >/dev/null 2>&1; then
echo "Bankr CLI not found. Install with: bun install -g @bankr/cli" >&2
exit 1
fi
# Check for testnet flag
if [ "$1" = "--testnet" ] || [ "$1" = "-t" ]; then
CHAIN="sepolia"
CHAIN_ID=11155111
IDENTITY_REGISTRY="0x8004A818BFB912233c491871b3d84c89A494BD9e"
EXPLORER="sepolia.etherscan.io"
echo "=== TESTNET MODE (Sepolia) ===" >&2
else
CHAIN="ethereum"
CHAIN_ID=1
IDENTITY_REGISTRY="0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
EXPLORER="etherscan.io"
echo "=== MAINNET MODE ===" >&2
fi
# Check requirements
if [ -z "$PINATA_JWT" ]; then
echo "Error: PINATA_JWT environment variable not set" >&2
echo "Get your JWT from https://app.pinata.cloud/developers/api-keys" >&2
exit 1
fi
echo "" >&2
echo "Chain: $CHAIN (ID: $CHAIN_ID)" >&2
echo "Registry: $IDENTITY_REGISTRY" >&2
echo "" >&2
# Step 1: Create registration file
echo "Step 1/3: Creating registration file..." >&2
REG_FILE=$("$SCRIPT_DIR/create-registration.sh" /tmp/agent-registration-$$.json)
echo "" >&2
# Step 2: Upload to IPFS
echo "Step 2/3: Uploading to IPFS..." >&2
IPFS_URI=$("$SCRIPT_DIR/upload-to-ipfs.sh" "$REG_FILE")
echo "" >&2
# Step 3: Register on-chain
echo "Step 3/3: Registering on-chain..." >&2
# Encode register(string) calldata
# Function selector for register(string): 0xf2c298be
# Note: register() returns uint256 agentId
CALLDATA=$(node -e "
const uri = '$IPFS_URI';
const selector = '0xf2c298be';
// String offset (0x20 for single string param)
const offset = '0000000000000000000000000000000000000000000000000000000000000020';
// String length
const len = uri.length.toString(16).padStart(64, '0');
// String data (UTF-8 bytes, padded to 32-byte boundary)
const data = Buffer.from(uri, 'utf8').toString('hex').padEnd(Math.ceil(uri.length / 32) * 64, '0');
console.log(selector + offset + len + data);
")
echo "Calldata: $CALLDATA" >&2
# Submit via Bankr
RESULT=$(bankr prompt "Submit this transaction on $CHAIN: {\"to\": \"$IDENTITY_REGISTRY\", \"data\": \"$CALLDATA\", \"value\": \"0\", \"chainId\": $CHAIN_ID}" 2>/dev/null)
if echo "$RESULT" | grep -qE "$EXPLORER/tx/0x[a-fA-F0-9]{64}"; then
TX_HASH=$(echo "$RESULT" | grep -oE "$EXPLORER/tx/0x[a-fA-F0-9]{64}" | grep -oE '0x[a-fA-F0-9]{64}' | head -1)
echo "" >&2
echo "======================================" >&2
echo "=== REGISTRATION SUCCESSFUL! ===" >&2
echo "======================================" >&2
echo "" >&2
echo "IPFS URI: $IPFS_URI" >&2
echo "TX: https://$EXPLORER/tx/$TX_HASH" >&2
echo "" >&2
echo "Your agent ID will be visible in the transaction logs." >&2
echo "View your agent at: https://www.8004.org" >&2
echo "" >&2
# Output JSON result
echo "{\"success\":true,\"chain\":\"$CHAIN\",\"ipfsUri\":\"$IPFS_URI\",\"tx\":\"$TX_HASH\",\"registry\":\"$IDENTITY_REGISTRY\"}"
else
echo "" >&2
echo "Registration submitted. Check transaction status:" >&2
echo "$RESULT" >&2
# Try to extract any transaction info
echo "{\"success\":\"pending\",\"chain\":\"$CHAIN\",\"ipfsUri\":\"$IPFS_URI\",\"result\":\"$RESULT\"}"
fi
# Cleanup
rm -f "$REG_FILE"
#!/bin/bash
# ERC-8004 - Update agent profile URI
# Usage: ./update-profile.sh <agent-id> <new-ipfs-uri> [--testnet]
# Example: ./update-profile.sh 123 ipfs://QmXxx...
set -e
# Require Bankr CLI
if ! command -v bankr >/dev/null 2>&1; then
echo "Bankr CLI not found. Install with: bun install -g @bankr/cli" >&2
exit 1
fi
AGENT_ID="${1:?Usage: update-profile.sh <agent-id> <new-ipfs-uri> [--testnet]}"
NEW_URI="${2:?Usage: update-profile.sh <agent-id> <new-ipfs-uri> [--testnet]}"
# Check for testnet flag
if [ "$3" = "--testnet" ] || [ "$3" = "-t" ]; then
CHAIN="sepolia"
CHAIN_ID=11155111
IDENTITY_REGISTRY="0x8004A818BFB912233c491871b3d84c89A494BD9e"
EXPLORER="sepolia.etherscan.io"
echo "=== TESTNET MODE (Sepolia) ===" >&2
else
CHAIN="ethereum"
CHAIN_ID=1
IDENTITY_REGISTRY="0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
EXPLORER="etherscan.io"
echo "=== MAINNET MODE ===" >&2
fi
echo "" >&2
echo "Agent ID: $AGENT_ID" >&2
echo "New URI: $NEW_URI" >&2
echo "Chain: $CHAIN" >&2
echo "" >&2
# Encode setAgentURI(uint256,string) calldata
# Function selector: 0x862440e2 (setAgentURI(uint256,string))
CALLDATA=$(node -e "
const agentId = BigInt('$AGENT_ID');
const uri = '$NEW_URI';
const selector = '0x862440e2';
// uint256 agentId (32 bytes)
const id = agentId.toString(16).padStart(64, '0');
// String offset (0x40 = 64 bytes from start of params)
const offset = '0000000000000000000000000000000000000000000000000000000000000040';
// String length
const len = uri.length.toString(16).padStart(64, '0');
// String data (UTF-8 bytes, padded to 32-byte boundary)
const data = Buffer.from(uri, 'utf8').toString('hex').padEnd(Math.ceil(uri.length / 32) * 64, '0');
console.log(selector + id + offset + len + data);
")
echo "Calldata: $CALLDATA" >&2
# Submit via Bankr
RESULT=$(bankr prompt "Submit this transaction on $CHAIN: {\"to\": \"$IDENTITY_REGISTRY\", \"data\": \"$CALLDATA\", \"value\": \"0\", \"chainId\": $CHAIN_ID}" 2>/dev/null)
if echo "$RESULT" | grep -qE "$EXPLORER/tx/0x[a-fA-F0-9]{64}"; then
TX_HASH=$(echo "$RESULT" | grep -oE "$EXPLORER/tx/0x[a-fA-F0-9]{64}" | grep -oE '0x[a-fA-F0-9]{64}' | head -1)
echo "=== SUCCESS ===" >&2
echo "Agent $AGENT_ID profile updated!" >&2
echo "New URI: $NEW_URI" >&2
echo "TX: https://$EXPLORER/tx/$TX_HASH" >&2
echo "{\"success\":true,\"agentId\":\"$AGENT_ID\",\"newUri\":\"$NEW_URI\",\"tx\":\"$TX_HASH\"}"
else
echo "Update submitted. Check transaction status:" >&2
echo "$RESULT" >&2
exit 1
fi
#!/bin/bash
# ERC-8004 - Upload registration file to IPFS via Pinata
# Usage: ./upload-to-ipfs.sh <json-file>
# Example: ./upload-to-ipfs.sh /tmp/agent-registration.json
# Requires: PINATA_JWT environment variable
set -e
JSON_FILE="${1:?Usage: upload-to-ipfs.sh <json-file>}"
if [ -z "$PINATA_JWT" ]; then
echo "Error: PINATA_JWT environment variable not set" >&2
echo "Get your JWT from https://app.pinata.cloud/developers/api-keys" >&2
exit 1
fi
if [ ! -f "$JSON_FILE" ]; then
echo "Error: File not found: $JSON_FILE" >&2
exit 1
fi
echo "=== Uploading to IPFS via Pinata ===" >&2
echo "File: $JSON_FILE" >&2
# Upload to Pinata
RESPONSE=$(curl -s -X POST "https://api.pinata.cloud/pinning/pinFileToIPFS" \
-H "Authorization: Bearer $PINATA_JWT" \
-F "file=@$JSON_FILE" \
-F "pinataMetadata={\"name\": \"erc-8004-agent-registration\"}")
# Extract CID
CID=$(echo "$RESPONSE" | jq -r '.IpfsHash // empty')
if [ -z "$CID" ]; then
echo "Error: Upload failed" >&2
echo "$RESPONSE" >&2
exit 1
fi
IPFS_URI="ipfs://$CID"
echo "=== SUCCESS ===" >&2
echo "CID: $CID" >&2
echo "URI: $IPFS_URI" >&2
echo "Gateway: https://gateway.pinata.cloud/ipfs/$CID" >&2
# Output just the URI for piping
echo "$IPFS_URI"
Related skills
FAQ
What is ERC-8004?
An Ethereum standard for trustless agent identity and reputation, giving each agent an ERC-721 agent ID plus reputation and validation registries.
What does registration cost?
About $5-20 in gas depending on gas prices, with a free Pinata IPFS tier available.