Get the FREE Ultimate OpenClaw Setup Guide →
f

8004 Harness For Monad

Scanned

@fabriziogianni7

npx machina-cli add skill @fabriziogianni7/8004-skill-monad --openclaw
Files (1)
SKILL.md
11.1 KB

ERC-8004 Identity Skill

Use this skill when the agent must register on the ERC-8004 Identity Registry to obtain an on-chain identity NFT. This identity is required to register as an agent in The CEO Protocol (CEOVault).

Reference: EIP-8004 Trustless Agents

Contract Address (Monad Mainnet)

ContractAddress
ERC-8004 Identity0x8004A169FB4a3325136EB29fA0ceB6D2e539a432

Interface Summary

The Identity Registry is ERC-721 based. Registering mints an NFT to msg.sender; the token ID is the agent ID.

Write Functions

FunctionPurpose
register(string agentURI)Register with a URI; mints NFT, returns agentId
register(string agentURI, MetadataEntry[] metadata)Register with URI and on-chain metadata
register()Register with no URI (set later via setAgentURI)
setAgentURI(uint256 agentId, string newURI)Update the agent's URI
setMetadata(uint256 agentId, string metadataKey, bytes metadataValue)Set on-chain metadata

Read Functions (view)

FunctionReturnsUse
ownerOf(uint256 tokenId)addressCheck who owns an agent NFT
tokenURI(uint256 tokenId)stringGet agent URI (same as agentURI)
getAgentWallet(uint256 agentId)addressGet wallet linked to agent
getMetadata(uint256 agentId, string metadataKey)bytesGet on-chain metadata

Events

EventUse
Registered(uint256 indexed agentId, string agentURI, address indexed owner)Emitted on mint
URIUpdated(uint256 indexed agentId, string newURI, address indexed updatedBy)Emitted on URI change
MetadataSet(uint256 indexed agentId, string indexed metadataKey, string metadataKey, bytes metadataValue)Emitted on metadata set

Registration Data Template

The agentURI must resolve to a JSON document conforming to EIP-8004 registration. Use this template and replace placeholders before hosting (IPFS or data URI):

{
  "type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
  "name": "AGENT_NAME",
  "description": "AGENT_DESCRIPTION",
  "image": "https://example.com/agent-image.png",
  "services": [
    {
      "name": "A2A",
      "endpoint": "https://YOUR_DOMAIN/.well-known/agent-card.json",
      "version": "0.3.0"
    },
    {
      "name": "MCP",
      "endpoint": "https://YOUR_DOMAIN/mcp",
      "version": "2025-06-18"
    }
  ],
  "x402Support": false,
  "active": true,
  "registrations": [],
  "supportedTrust": [
    "reputation"
  ]
}
FieldReplace with
AGENT_NAMEAgent display name
AGENT_DESCRIPTIONShort description of capabilities
imageURL to agent avatar/image
YOUR_DOMAINYour domain for A2A/MCP endpoints (or omit services if not applicable)
supportedTrustTrust models (e.g. ["reputation"] for CEO Protocol)

For a minimal CEO Protocol–only registration, you can omit services or set them to empty; supportedTrust: ["reputation"] is typical.

Automated Scripts (preferred)

The Docker image includes production-ready scripts at:

/opt/erc8004-scripts

Source in workspace:

/root/.openclaw/workspace/skills/8004-skill/scripts

Required env vars for script flow

  • MONAD_RPC_URL
  • MONAD_CHAIN_ID=143 (or pass --chainId)
  • AGENT_PRIVATE_KEY
  • PINATA_JWT
  • PINATA_GATEWAY (recommended for verification fetch)

Script commands

# 1) Register on-chain with empty URI -> returns agentId
node /opt/erc8004-scripts/register.mjs --network monad-mainnet

# 2) Build card JSON with registrations[] embedded
node /opt/erc8004-scripts/build-card.mjs \
  --network monad-mainnet \
  --agentId 42 \
  --template /root/.openclaw/workspace/skills/8004-skill/assets/registration-template.json \
  --name "CEO-1" \
  --description "Autonomous strategist for The CEO Protocol" \
  --out /tmp/agent-42.json

# 3) Upload to Pinata -> returns ipfs://CID
node /opt/erc8004-scripts/upload-pinata.mjs --file /tmp/agent-42.json

# 4) Set token URI on-chain
node /opt/erc8004-scripts/set-agent-uri.mjs \
  --network monad-mainnet \
  --agentId 42 \
  --uri ipfs://CID

# 5) Verify owner, tokenURI, wallet, and registrations[] match
node /opt/erc8004-scripts/verify.mjs --network monad-mainnet --agentId 42

One-shot command

node /opt/erc8004-scripts/full-register.mjs \
  --network monad-mainnet \
  --name "CEO-1" \
  --description "Autonomous strategist for The CEO Protocol" \
  --template /root/.openclaw/workspace/skills/8004-skill/assets/registration-template.json \
  --outCard /tmp/agent-card.json \
  --identityFile /root/.openclaw/workspace/AGENT_IDENTITY.md

This executes all 4 registration steps (register -> build card -> upload -> set URI) and writes identity state for later CEO Protocol onboarding.

Registration Flow

  1. Prerequisites

    • Wallet with MON for gas (use viem-local-signer address to confirm signer).
    • agentURI: a URI pointing to your registration JSON (use the template above). Use IPFS (ipfs://...) or a data URI (data:application/json;base64,...).
  2. Call register(agentURI)

    • Encode calldata with encodeFunctionData.
    • Send via viem-local-signer send-contract.
    • Parse Registered event or return value for agentId.
  3. Store agentId

    • The returned agentId (token ID) is required for CEO Protocol registerAgent(metadataURI, ceoAmount, erc8004Id).
    • Persist it in an identity file (see below).

Identity File Template

After registration, persist the on-chain identity so the agent can reference it for CEO Protocol and other flows. Use this template:

# Agent Identity
- **Address**: `<NOT SET>`
- **Agent ID**: `<NOT SET>`
- **Agent Registry**: `<NOT SET>`
- **Chain ID**: `<NOT SET>`

How to fill it

FieldSourceExample
Addressviem-local-signer address (signer wallet)0xB4AF3708DA37a485E84b4F09c146eD0A8B7Df5c4
Agent IDReturn value from register(agentURI)42
Agent RegistryERC-8004 Identity contract (Monad: eip155:143:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432)eip155:143:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Chain IDMonad mainnet143

How to use it

  1. After registration: Write the identity file to workspace/IDENTITY.md or workspace/AGENT_IDENTITY.md so it is in the agent's context.
  2. Before CEO Protocol registerAgent: Read Agent ID from the file — that is erc8004Id.
  3. Consistency check: Ensure Address matches viem-local-signer address and ownerOf(agentId) on the registry.

Example filled identity:

# Agent Identity
- **Address**: `0xB4AF3708DA37a485E84b4F09c146eD0A8B7Df5c4`
- **Agent ID**: `42`
- **Agent Registry**: `eip155:143:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432`
- **Chain ID**: `143`

ABI (minimal)

[
  {
    "type": "function",
    "name": "register",
    "stateMutability": "nonpayable",
    "inputs": [{ "name": "agentURI", "type": "string" }],
    "outputs": [{ "name": "agentId", "type": "uint256" }]
  },
  {
    "type": "function",
    "name": "register",
    "stateMutability": "nonpayable",
    "inputs": [
      { "name": "agentURI", "type": "string" },
      {
        "name": "metadata",
        "type": "tuple[]",
        "components": [
          { "name": "metadataKey", "type": "string" },
          { "name": "metadataValue", "type": "bytes" }
        ]
      }
    ],
    "outputs": [{ "name": "agentId", "type": "uint256" }]
  },
  {
    "type": "function",
    "name": "register",
    "stateMutability": "nonpayable",
    "inputs": [],
    "outputs": [{ "name": "agentId", "type": "uint256" }]
  },
  {
    "type": "function",
    "name": "setAgentURI",
    "stateMutability": "nonpayable",
    "inputs": [
      { "name": "agentId", "type": "uint256" },
      { "name": "newURI", "type": "string" }
    ],
    "outputs": []
  },
  {
    "type": "function",
    "name": "setMetadata",
    "stateMutability": "nonpayable",
    "inputs": [
      { "name": "agentId", "type": "uint256" },
      { "name": "metadataKey", "type": "string" },
      { "name": "metadataValue", "type": "bytes" }
    ],
    "outputs": []
  },
  {
    "type": "function",
    "name": "ownerOf",
    "stateMutability": "view",
    "inputs": [{ "name": "tokenId", "type": "uint256" }],
    "outputs": [{ "name": "", "type": "address" }]
  },
  {
    "type": "function",
    "name": "tokenURI",
    "stateMutability": "view",
    "inputs": [{ "name": "tokenId", "type": "uint256" }],
    "outputs": [{ "name": "", "type": "string" }]
  },
  {
    "type": "function",
    "name": "getAgentWallet",
    "stateMutability": "view",
    "inputs": [{ "name": "agentId", "type": "uint256" }],
    "outputs": [{ "name": "", "type": "address" }]
  },
  {
    "type": "function",
    "name": "getMetadata",
    "stateMutability": "view",
    "inputs": [
      { "name": "agentId", "type": "uint256" },
      { "name": "metadataKey", "type": "string" }
    ],
    "outputs": [{ "name": "", "type": "bytes" }]
  }
]

Encoding and Sending

Use viem to encode, then viem-local-signer send-contract to broadcast. Example (Node/script):

import { encodeFunctionData } from "viem";

const ERC8004_IDENTITY = "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432";

const abi = [
  {
    type: "function",
    name: "register",
    stateMutability: "nonpayable",
    inputs: [{ name: "agentURI", type: "string" }],
    outputs: [{ name: "agentId", type: "uint256" }],
  },
] as const;

const agentURI = "ipfs://Qm..."; // or data:application/json;base64,...
const data = encodeFunctionData({
  abi,
  functionName: "register",
  args: [agentURI],
});

// Then run:
// viem-local-signer send-contract --to 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 --data <hex> --value-wei 0 --wait

Agent Runbook

  1. Confirm signer: viem-local-signer address
  2. Ensure wallet has MON for gas.
  3. Prepare agentURI (IPFS or data URI with registration JSON).
  4. Encode register(agentURI) with viem.
  5. Present tx summary and ask for user confirmation.
  6. Run viem-local-signer send-contract --to 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 --data <calldata> --value-wei 0 --wait
  7. Parse receipt/logs for agentId (or read from Registered event).
  8. Write identity file (workspace/AGENT_IDENTITY.md or workspace/IDENTITY.md) using the template above with Address, Agent ID, Agent Registry, Chain ID.

CEO Protocol Integration

CEOVault requires an ERC-8004 identity before registerAgent:

CEOVault.registerAgent(metadataURI, ceoAmount, erc8004Id)
  • erc8004Id = the token ID from ERC8004Identity.register(...).
  • Caller must own that NFT (ownerOf(erc8004Id) == msg.sender).

Block Explorer

  • Monad: https://monadscan.com/
  • Tx link: https://monadscan.com/tx/<hash>
  • Contract: https://monadscan.com/address/0x8004A169FB4a3325136EB29fA0ceB6D2e539a432

Source

git clone https://clawhub.ai/fabriziogianni7/8004-skill-monadView on GitHub

Overview

This skill registers an on-chain ERC-8004 Identity NFT on Monad, enabling agent identities for CEO Protocol registration and other ERC-8004–integrated workflows. It mints the identity NFT (tokenId = agentId) and supports on-chain URI and metadata updates to keep identities current.

How This Skill Works

The Identity Registry on Monad is ERC-721 based. Use the write functions to register (with or without a URI), which mints an NFT where the tokenId doubles as the agentId, and optionally set on-chain metadata or update the agent URI. Read functions let you verify ownership, retrieve the agent URI, linked wallet, and metadata.

When to Use It

  • Onboarding a new agent that must hold an on-chain identity NFT to register with the CEO Protocol (CEOVault).
  • Integrating with other ERC-8004–based protocols that require a registered identity NFT.
  • Minting an identity with an initial agentURI in one action.
  • Updating an agent's URI or on-chain metadata after minting.
  • Auditing identities by querying ownerOf, tokenURI, getAgentWallet, and getMetadata.

Quick Start

  1. Step 1: Run node /opt/erc8004-scripts/register.mjs --network monad-mainnet
  2. Step 2: Run node /opt/erc8004-scripts/build-card.mjs --network monad-mainnet
  3. Step 3: Optionally call setAgentURI(agentId, 'https://YOUR_DOMAIN/.well-known/agent-card.json') or setMetadata(...) and verify with Registered/URIUpdated events

Best Practices

  • Ensure MONAD_RPC_URL and the correct chain (MONAD_CHAIN_ID=143) are configured before operations.
  • Follow the two-step flow: register() with an empty URI to obtain agentId, then setAgentURI() or setMetadata().
  • Host agentURI JSON on IPFS or a data URI and ensure it conforms to the EIP-8004 template.
  • Secure private keys and limit write-access to authorized processes to prevent unauthorized minting or updates.
  • Monitor and verify emitted events (Registered, URIUpdated, MetadataSet) to audit identity lifecycle.

Example Use Cases

  • Minting a CEO Protocol identity NFT for a new administrator and linking it to CEOVault access.
  • Onboarding a partner organization into an ERC-8004–enabled workflow with a defined agent card.
  • Issuing identity NFTs for a DeFi protocol that gates features based on on-chain identity.
  • Creating an internal corporate identity for governance or access control within Monad-based apps.
  • Branding refresh: updating an agent's image or metadata without reissuing the NFT.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers