
Erc 8004
- 14 installs
- 1.2k repo stars
- Updated August 1, 2026
- bankrbot/moltbot-skills
ERC-8004 is a Claude skill that registers an AI agent's identity and reputation on Ethereum mainnet using the ERC-8004 Trustless Agents standard.
About
ERC-8004 registers an AI agent's identity on Ethereum mainnet using the ERC-8004 Trustless Agents standard, minting an ERC-721 agent ID. A developer uses it to make an agent discoverable and to attach reputation and validation signals. It handles bridging ETH to mainnet, uploading the profile to IPFS, and calling register on the Identity Registry.
- Registers AI agents onchain via ERC-8004 Identity Registry (agent gets an NFT)
- Handles bridging ETH to mainnet, IPFS upload, and on-chain registration
- Four registration paths: 8004.org UI, HTTP URL, IPFS via Pinata, or fully on-chain data URI
Erc 8004 by the numbers
- 14 all-time installs (skills.sh)
- Ranked #11,296 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
Needs mainnet ETH (~$5-20 gas per registration) and an optional Pinata JWT; Pinata has a free 1GB tier.
- Capabilities
- agent identity registration · ipfs upload · eth bridging · onchain reputation
- Use cases
- orchestration
- Pricing
- Bring your own API key
What erc-8004 says it does
Register your AI agent on Ethereum mainnet with a verifiable on-chain identity, making it discoverable and enabling trust signals.
**Identity Registry** - ERC-721 based agent IDs (your agent gets an NFT!)
npx skills add https://github.com/bankrbot/moltbot-skills --skill erc-8004Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 14 |
|---|---|
| repo stars | ★ 1.2k |
| Last updated | August 1, 2026 |
| Repository | bankrbot/moltbot-skills ↗ |
What it does
Register an AI agent's identity on Ethereum mainnet using ERC-8004 (Trustless Agents) with IPFS profile and onchain registration.
Who is it for?
Developers who want an AI agent to have a verifiable, discoverable onchain identity with reputation signals.
Skip if: Projects that do not need onchain agent identity or cannot pay mainnet gas for registration.
When should I use this skill?
The user wants to register their agent identity on-chain, create an agent profile, claim an agent NFT, or set up agent reputation.
What you get
A registered ERC-8004 agent identity (NFT + agent ID) on Ethereum mainnet, discoverable with reputation support.
- Registered onchain agent identity (agent ID + NFT)
- IPFS-hosted agent registration file
By the numbers
- 4 registration options (UI, 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 does ERC-8004 provide?
An Identity Registry (ERC-721 agent IDs), a Reputation Registry for feedback, and a Validation Registry for third-party verification.
How much does registration cost?
About 100-200k gas for registration (roughly $5-20 depending on gas prices), with a free Pinata IPFS tier.