Abstract
This EIP introduces an extension to ERC-721 that enables NFTs to be associated with AI agents, including prompts and other agent settings. This extension allows a NFT token to store prompts and AI agentβs address, facilitating the establishment of an on-chain identity for AI-powered entities.
Motivation
As artificial intelligence becomes increasingly integrated with blockchain technology, there is a growing need for standardized interfaces that enable NFTs to interact with AI systems. Current ERC-721 tokens lack native support for AI integration. However, ERC-721 tokens are non-fungible, transferable, capable of storing data, and compatible with extensions such as ERC-6551 wallets. These characteristics make ERC-721 a suitable standard for serving as an on-chain identity for AI agents. At present, prompts and other relevant information are often stored in the NFT token URI without a standardized format, making recognition and application challenging. This extension addresses these limitations by providing:
- A decentralized on-chain identity for AI agents β By associating AI agents with AgentNFTs, this extension enables them to interact with smart contracts in a highly composable manner.
- A transferable and non-custodial asset type β AgentNFTs function as liquid assets, facilitating ownership transfers while preserving on-chain value.
- An interface for storage and management of prompts and AI agent addresses β Each AgentNFT securely maintains its associated AI agentβs address and prompt data, ensuring consistency and interoperability.
- Prompts and other data can be encrypted for privacy while remaining verifiable for authenticity.
Specification
The extension introduces the following interface:
/**
* @title IAgentNFT
* @dev Interface for ERC721 AgentNFT extension that adds prompt and agent management capabilities
* This extension allows NFTs to store and manage prompts and AI Agent's corresponding address
*/
interface IAgentNFT /* is IERC165, IERC721 */ {
/**
* @dev Emitted when an address is updated for a AgentNFT
* @param tokenId The ID of the AgentNFT
* @param agent The new agent address
*/
event AgentUpdated(uint256 indexed tokenId, address indexed agent);
/**
* @dev Emitted when a prompt is updated for a AgentNFT
* @param tokenId The ID of the AgentNFT
* @param prompt The new prompt string
*/
event PromptUpdated(uint256 indexed tokenId, string prompt);
/**
* @dev Returns the current address corresponding to the AgentNFT. The address can be a wallet address or smart contract address. The AI Agent is represented by the AgentNFT of the given tokenId parameter
* @param tokenId The ID of the AgentNFT to query
* @return The address of the associated AI agent
*/
function agent(uint256 tokenId) external view returns (address);
/**
* @dev Updates the address for an AgentNFT
* @param tokenId The ID of the AgentNFT to update
* @param newAgent The new agent address to assign
*/
function updateAgent(uint256 tokenId, address newAgent) external;
/**
* @dev Returns the current prompt for a AgentNFT
* @param tokenId The ID of the AgentNFT to query
* @return The prompt string associated with the AgentNFT
*/
function prompt(uint256 tokenId) external view returns (string memory);
/**
* @dev Updates the prompt for an AgentNFT
* @param tokenId The ID of the AgentNFT to update
* @param newPrompt The new prompt string to assign
*/
function updatePrompt(uint256 tokenId, string memory newPrompt) external;
}Rationale
This interface is designed to be minimal yet flexible, ensuring compatibility with various use cases:
- On-Chain Agent Prompts β Prompts are a core asset of AI agents. By storing them within AgentNFTs, they become transferable, preserving their value and utility.
- Agent Information Authentication β On-chain information can be used for identification and authentication, enhancing transparency and trust.
- Efficient State Querying β The interface enables seamless tracking and updating of agent information, facilitating efficient state management.
Backwards Compatibility
This extension is fully backwards compatible with ERC-721.
Reference Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IAgentNFT } from "./IAgentNFT.sol";
/**
* @title AgentNFT
* @dev Implementation of IAgentNFT, which adds prompt and agent management capabilities extension to ERC721
* This extension allows NFTs to store and manage prompts and AI Agent's corresponding address
*/
contract AgentNFT is ERC721, IAgentNFT, Ownable {
// Mapping from token ID to AI agent address
mapping(uint256 => address) private _agents;
// Mapping from token ID to prompt string
mapping(uint256 => string) private _prompts;
/**
* @dev Initializes the contract by setting a name and symbol to the AgentNFT collection
* @param name The name of the AgentNFT collection
* @param symbol The symbol of the AgentNFT collection
*/
constructor(string memory name, string memory symbol)
ERC721(name, symbol)
Ownable(msg.sender)
{}
/**
* @dev Safely mints a new AgentNFT
* @param to The address that will own the minted AgentNFT
* @param tokenId The AgentNFT id to mint
*/
function safeMint(address to, uint256 tokenId) public onlyOwner {
_safeMint(to, tokenId);
}
/**
* @dev See {IAgentNFT}
* Requirements:
* - Token must exist
*/
function agent(uint256 tokenId) public view override returns (address) {
require(ownerOf(tokenId) != address(0), "AgentNFT: token does not exist");
return _agents[tokenId];
}
/**
* @dev See {IAgentNFT-updateAgent}
* Requirements:
* - Caller must be token owner or approved
* - New agent address must not be zero address
*/
function updateAgent(uint256 tokenId, address newAgent) public override {
require(ownerOf(tokenId) == msg.sender,
"AgentNFT: caller is not owner nor approved");
require(newAgent != address(0),
"AgentNFT: new agent is zero address");
_agents[tokenId] = newAgent;
emit AgentUpdated(tokenId, newAgent);
}
/**
* @dev See {IAgentNFT-prompt}
* Requirements:
* - Token must exist
*/
function prompt(uint256 tokenId) public view override returns (string memory) {
return _prompts[tokenId];
}
/**
* @dev See {IAgentNFT-updatePrompt}
* Requirements:
* - Caller must be token owner, approved, or the assigned agent
* - New prompt must not be empty
*/
function updatePrompt(uint256 tokenId, string memory newPrompt) public override {
require(
ownerOf(tokenId) == msg.sender || getApproved(tokenId) == msg.sender || isApprovedForAll(ownerOf(tokenId), msg.sender) || msg.sender == _agents[tokenId],
"AgentNFT: caller is not owner, approved, or agent"
);
_prompts[tokenId] = newPrompt;
emit PromptUpdated(tokenId, newPrompt);
}
} The reference implementation includes:
- Storage mappings for agents and prompts
- Events emission on state changes
- Input validation
- Full compatibility with ERC-721
Security Considerations
- Access Control
- Only token owners or approved operators should be able to update agents and prompts
- Implementations should validate agent addresses
- Storage Considerations
- Implementations should consider limiting prompt string length
- Data such as prompts can be encrypted for privacy, but need to be verifiable
- Gas costs for prompt storage and updates
Copyright
Copyright and related rights waived via CC0.
