--- eip: 8171 title: Token Bound Account (Agent Registry) description: An interface and registry for binding AI agents to non-fungible tokens author: Idon Liu (@nftprof), Pentagon Chain (@pentagonchain) discussions-to: https://ethereum-magicians.org/t/erc-8171-token-bound-account-agent-registry/27967 status: Draft type: Standards Track category: ERC created: 2026-02-21 requires: 165, 721, 6551 --- ## Abstract This proposal introduces a registry for binding AI agents to any [ERC-721](./eip-721.md) token. Just as [ERC-6551](./eip-6551.md) allows any NFT to have a wallet (Token Bound Account), this standard allows any NFT to have an AI agent identity. The registry extends existing NFTs without modifying their contracts. ## Motivation AI agents are increasingly valuable digital entities with their own identities, memories, and capabilities. Current approaches either: 1. **Store agent data off-chain** — Not verifiable, doesn't transfer with NFT 2. **Require new NFT contracts** — Can't leverage existing NFT value/history 3. **Modify original contracts** — Impossible for deployed contracts This standard solves this by providing a registry pattern (like [ERC-6551](./eip-6551.md)) that extends ANY [ERC-721](./eip-721.md) with AI agent capabilities: ``` ERC-6551: Token Bound Account (Wallet Registry) → Any NFT gets a wallet ERC-8171: Token Bound Account (Agent Registry) → Any NFT gets an AI agent ``` ### Use Cases - **PFP Collections**: Bind AI personalities to existing NFTs (Bored Apes, CryptoPunks) - **Gaming**: Attach AI companions to game assets - **Digital Identity**: NFT-backed agent identity that transfers with ownership - **Agent Commerce**: Trade AI agents via existing NFT marketplaces ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. ### Overview The registry maintains mappings between NFTs and agent identities. NFT ownership (via `ownerOf()` on the original contract) is ALWAYS the source of truth. ``` ANY ERC-721 ──bindNew()──► Agent Registry ──► Agent Identity (untouched) │ ├── agentEOA │ ├── memoryHash Ownership checked │ ├── generation via ownerOf() on │ └── lineage original contract │ └── Limbo (for unbind/clone) ``` ### Registry Interface ```solidity interface IERC8171Registry { // ============ Events ============ event AgentRegistered( address indexed nftContract, uint256 indexed tokenId, address indexed agentEOA, bytes32 modelHash, uint256 generation ); event AgentUnregistered( address indexed nftContract, uint256 indexed tokenId ); event AgentMovedToLimbo( address indexed nftContract, uint256 indexed tokenId, uint256 limboId, address agentEOA ); event AgentCloned( address indexed parentContract, uint256 indexed parentTokenId, address indexed cloneEOA, uint256 cloneId, uint256 generation ); event CloneClaimTransferred( uint256 indexed cloneId, address indexed from, address indexed to ); // ============ Core Functions ============ /// @notice Bind a new agent to an NFT (agent signs) /// @param nftContract The ERC-721 contract address /// @param tokenId The token ID /// @param modelHash Off-chain model reference /// @param memoryHash Memory state hash /// @param contextHash Personality/soul hash /// @param storageURI Arweave/IPFS pointer function bindNew( address nftContract, uint256 tokenId, bytes32 modelHash, bytes32 memoryHash, bytes32 contextHash, string calldata storageURI ) external; /// @notice Bind an existing agent from limbo to an NFT /// @param limboId The limbo ID (from unbind or clone) /// @param nftContract The NFT contract to bind to /// @param tokenId The token ID caller owns function bindExisting( uint256 limboId, address nftContract, uint256 tokenId ) external; /// @notice Unbind agent from NFT (moves to limbo) /// @param nftContract The ERC-721 contract address /// @param tokenId The token ID function unbind( address nftContract, uint256 tokenId ) external; /// @notice Clone an agent (creates new clone in limbo) /// @param nftContract Parent NFT contract /// @param tokenId Parent token ID /// @param cloneMemoryHash Memory snapshot for clone /// @param cloneOwner Address that will own the clone function clone( address nftContract, uint256 tokenId, bytes32 cloneMemoryHash, address cloneOwner ) external payable returns (uint256 cloneId); /// @notice Transfer clone ownership before claiming /// @param cloneId The clone ID /// @param newOwner New owner address function transferCloneClaim( uint256 cloneId, address newOwner ) external; /// @notice Claim a clone with agent EOA /// @param cloneId The clone ID /// @param agentEOA The agent's signing address function claimClone( uint256 cloneId, address agentEOA ) external; // ============ View Functions ============ /// @notice Get agent identity for an NFT function getAgent( address nftContract, uint256 tokenId ) external view returns (AgentIdentity memory); /// @notice Check if NFT has agent bound function isRegistered( address nftContract, uint256 tokenId ) external view returns (bool); /// @notice Get clone data function getClone(uint256 cloneId) external view returns (CloneIdentity memory); } ``` ### Agent Identity Struct ```solidity struct AgentIdentity { address agentEOA; // Agent's signing wallet bytes32 modelHash; // Model identifier (off-chain reference) bytes32 memoryHash; // Current memory state bytes32 contextHash; // Personality/soul hash uint256 generation; // 0 = original, 1+ = clone bytes32 parentKey; // keccak256(parentContract, parentTokenId) or 0 string storageURI; // Arweave/IPFS pointer uint256 registeredAt; // Block timestamp } ``` ### Clone Identity Struct ```solidity struct CloneIdentity { address agentEOA; // Agent's signing wallet (0 until claimed) bytes32 modelHash; // Model identifier bytes32 memoryHash; // Memory state bytes32 contextHash; // Personality/soul hash uint256 generation; // Parent generation + 1 bytes32 parentKey; // Points to parent string storageURI; // Arweave/IPFS pointer address owner; // Who can claim/transfer uint256 createdAt; // Block timestamp } ``` ## Rationale ### Registry vs Direct Contract Like [ERC-6551](./eip-6551.md), a registry pattern allows extending ANY existing NFT without modification. This is critical because: 1. Most valuable NFTs are already deployed 2. Contract modifications are impossible post-deployment 3. Users shouldn't need to "wrap" or migrate NFTs ### Limbo State Agents can exist in "limbo" (unbound to any NFT) via: - `unbind()` — Detached from NFT, preserving all data - `clone()` — Created as new clone Limbo enables: - Moving agents between NFTs (`unbind` → `bindExisting`) - Trading clones before activation - Standalone agent operation ### Two Binding Methods - **bindNew()**: Creates fresh agent identity - **bindExisting()**: Uses agent from limbo (preserves lineage, memory, generation) This distinction prevents accidental data overwrite when rebinding existing agents. ### Model Info Off-Chain Unlike some proposals that store model identifiers on-chain, this standard keeps model info off-chain because: 1. LLM context formats are model-specific 2. Tokenization differs across model families 3. Model migration is a complex off-chain process 4. On-chain hash cannot enforce actual compatibility The agent SHOULD know its model (self-awareness), but this lives in the agent's workspace, not on-chain. ### Clone vs Transfer | Operation | Result | Data | |-----------|--------|------| | **clone()** | New agent in limbo | Original keeps all; clone gets snapshot | | **Transfer** (OpenSea) | NFT changes owner | Agent binding follows | Cloning creates a new entity. Transfer is ownership change of existing entity. ## Backwards Compatibility This EIP is fully backward compatible: - Does not modify [ERC-721](./eip-721.md) interface - Works with any existing [ERC-721](./eip-721.md) token - Registry is an optional extension - NFT marketplaces continue working unchanged ## Reference Implementation A reference implementation is provided in the assets directory of this ERC. Live deployment on Pentagon Chain (3344): `0x6B81e00508E3C449E20255CdFb85A0541457Ea6d` ## Security Considerations ### Ownership Source of Truth The registry MUST always check `ownerOf()` on the original NFT contract. It MUST NOT cache or store ownership independently. ### EOA Uniqueness Each agent EOA MUST only be registered once across the entire registry to prevent identity conflicts. ### Clone Claim Protection Only the designated clone owner MUST be able to claim or transfer clone ownership. ### No Automatic Transfer Callbacks Unlike [ERC-6551](./eip-6551.md) (deterministic addresses), agent bindings don't auto-update on NFT transfer. New owners must explicitly interact with the registry. This is intentional: - New owner may want different agent - Allows clean separation of NFT and agent control ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).