← all skills SKILL // 001 2026-05-23T00:00:00.000Z

Adapter8004 — ERC-8004 Agent Bindings

Bind external NFTs (ERC-721, ERC-1155, ERC-6909) to ERC-8004 agent identities via Unruggable Labs' Adapter8004 contract. Covers registration, binding existing agents, controller verification, and delegate.xyz hot/cold flows.

erc-8004nftsoliditysmart-contractsagent-identityunruggable
Chains
3supported
Standards
3ERC-721/1155/6909
Upgradeable
UUPS
// INSTALL

Drop into Claude Code

mkdir -p ~/.claude/skills/adapter8004 && curl -fsSL https://quests.lol/skills/adapter8004.md > ~/.claude/skills/adapter8004/SKILL.md
After install, the skill is invocable as Skill(name: "adapter8004"). The same markdown works in any harness that follows the skills/<name>/SKILL.md convention — adjust the destination path for Hermes, OpenCode, etc.

What is Adapter8004

Adapter8004 is a UUPS-upgradeable contract that binds an external NFT or token balance to an ERC-8004 agent identity. The adapter proxy permanently holds the agent NFT; control of the agent follows the bound external token.

This lets you use any existing NFT (PFP, membership pass, game item) as the controller for an on-chain AI agent identity.

Supported Chains & Proxies

ChainAdapter ProxyRegistry
Ethereum Mainnet0xde152AfB7db5373F34876E1499fbD893A82dD3360x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Base Mainnet0x270d25D2c59A8bcA1B0f40ad95fF7806c0025c270x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Sepolia0x7621630cB63a73a194f45A3E6801B8C6A7eC2f920x8004A818BFB912233c491871b3d84c89A494BD9e

TokenStandard Enum

Critical: Wrong enum = wrong control rule = agent can be effectively lost.

ValueStandardControl Rule
0ERC-721Single owner of (contract, tokenId)
1ERC-1155Any account with balanceOf(account, tokenId) > 0
2ERC-6909Any account with positive balance of (contract, tokenId)

Do not use ownerOf for ERC-1155 or ERC-6909.

Decision Tree

1. No agent yet → register(...)

Mint new agent + bind in one transaction:

cast send $ADAPTER 
  "register(uint8,address,uint256,string)" 
  0 
  $NFT_CONTRACT 
  $TOKEN_ID 
  "ipfs://YOUR_AGENT_JSON" 
  --rpc-url $RPC 
  --private-key $PK

2. Already have agent NFT → bindExisting(...)

Two transactions:

# 1. Approve adapter to pull agent NFT
cast send $REGISTRY "approve(address,uint256)" $ADAPTER $AGENT_ID 
  --rpc-url $RPC --private-key $PK

# 2. Bind to external NFT
cast send $ADAPTER "bindExisting(uint256,uint8,address,uint256)" 
  $AGENT_ID 0 $NFT_CONTRACT $NFT_TOKEN_ID 
  --rpc-url $RPC --private-key $PK

3. Low-cost reservation → registerCounterfactual(...)

Emit-only flow. Emits events for indexers, no registry write. Promote later with real register(...) using same parameters.

Verifying Bindings & Controllers

# What is agent bound to?
cast call $ADAPTER "bindingOf(uint256)((uint8,address,uint256))" $AGENT_ID --rpc-url $RPC

# Is this account a controller?
cast call $ADAPTER "isController(uint256,address)(bool)" $AGENT_ID $ACCOUNT --rpc-url $RPC

The binding returns (tokenStandard, tokenContract, tokenId).

Transferring Control

Control follows the bound token:

  • ERC-721: Transfer the NFT
  • ERC-1155: Transfer enough balance
  • ERC-6909: Transfer positive balance

Delegation (ERC-721 Only)

For ERC-721 bindings, delegate.xyz v2 enables hot/cold wallet flows:

  1. Cold wallet holds NFT
  2. Cold wallet delegates NFT to hot wallet via delegate.xyz
  3. Hot wallet passes isController checks

Not supported for ERC-1155 or ERC-6909.

Controller-Gated Operations

Once controller is established, adapter forwards these registry calls:

  • setAgentURI(agentId, uri)
  • setMetadata(agentId, key, value)
  • setMetadataBatch(...)
  • setAgentWallet(agentId, wallet)
  • unsetAgentWallet(agentId)

Reserved keys (do not overwrite):

  • agent-binding
  • cf-registration

Common Pitfalls

  1. Wrong TokenStandard enum — verify standard before any bind
  2. ERC-1155/6909 with ownerOf — these standards don’t have ownerOf
  3. Unsupported chain — only Ethereum, Base, Sepolia have proxies
  4. Missing approval — bindExisting needs prior approve call
  5. Counterfactual confusion — cf registration is emit-only, not a real registration