A standard interface for NFTs specifically designed for AI agents, where the metadata represents agent capabilities and requires privacy protection. Unlike traditional NFT standards that focus on static metadata, this standard introduces mechanisms for verifiable data ownership and secure transfer. By defining a unified interface for different verification methods (e.g., Trusted Execution Environment (TEE), Zero-Knowledge Proof (ZKP)), it enables secure management of valuable agent metadata such as models, memory, and character definitions, while maintaining confidentiality and verifiability.
With the increasing intelligence of AI models, agents have become powerful tools for automating meaningful daily tasks. The integration of agents with blockchain technology has been recognized as a major narrative in the crypto industry, with many projects enabling agent creation for their users. However, a crucial missing piece is the decentralized management of agent ownership.
AI agents possess inherent non-fungible properties that make them natural candidates for NFT representation:
However, current NFT standards like ERC-721 are insufficient for representing AI agents as digital assets. While NFTs can establish ownership of digital items, using them to represent AI agents introduces unique challenges. The key issue lies in the metadata transfer mechanism. Unlike traditional NFTs where metadata is typically static and publicly accessible, an AI agent's metadata (which constitutes the agent itself):
For example, when transferring an agent NFT, we need to ensure:
This EIP introduces a standard for NFTs with private metadata that addresses these requirements through privacy-preserving verification mechanisms, enabling secure ownership and transfer of valuable agent data while maintaining confidentiality and verifiability. This standard will serve as a foundation for the emerging agent ecosystem, allowing platforms to provide verifiable agent ownership and secure metadata management in a decentralized manner.
The EIP defines three key interfaces: the main NFT interface, the metadata interface, and the data verification interface.
The verification system consists of two core components that work together to ensure secure data operations:
Can be implemented using different verification mechanisms (TEE/ZKP)
Off-chain Prover
The system supports two types of proofs:
Verified on-chain through verifyOwnership()
Transfer Validity Proof
verifyTransferValidity()
The ownership verification is optional because when the minted token is transferred or cloned, the ownership verification is checked again inside the availability verification. It's better to be safe than sorry, so we recommend doing ownership verification for minting and updates.
Different verification mechanisms have distinct capabilities:
Verifier checks TEE attestations
ZKP-based Implementation
/// @notice Output of ownership proof verification
struct OwnershipProofOutput {
bytes32[] dataHashes;
bool isValid;
}
/// @notice Output of transfer validity proof verification
struct TransferValidityProofOutput {
bytes32[] oldDataHashes;
bytes32[] newDataHashes;
bytes pubKey;
bytes sealedKey;
bool isValid;
}
/// @notice Verify ownership of data
/// @param _proof Proof generated by companion prover system
/// @return Verification result and validated data hashes
function verifyOwnership(
bytes calldata _proof
) external view returns (OwnershipProofOutput memory);
/// @notice Verify data transfer validity
/// @param _proof Proof generated by companion prover system
/// @return Verification result and transfer details
function verifyTransferValidity(
bytes calldata _proof
) external view returns (TransferValidityProofOutput memory);
/// @dev This emits when data is updated
event Updated(
uint256 indexed _tokenId,
bytes32[] _oldDataHashes,
bytes32[] _newDataHashes
);
/// @notice Get the name of the NFT collection
function name() external view returns (string memory);
/// @notice Get the symbol of the NFT collection
function symbol() external view returns (string memory);
/// @notice Get the metadata URI for a specific token
function tokenURI(uint256 tokenId) external view returns (string memory);
/// @notice Update data
/// @param _tokenId The token to update
/// @param _proofs Proof of updated data ownership
function update(
uint256 _tokenId,
bytes[] calldata _proofs
) external;
/// @notice Get the data hash of a token
/// @param _tokenId The token identifier
/// @return The current data hash of the token
function dataHashesOf(uint256 _tokenId) public view returns (bytes32[] memory);
/// @notice Get the data description of a token
/// @param _tokenId The token identifier
/// @return The current data description of the token
function dataDescriptionsOf(uint256 _tokenId) public view returns (string[] memory);
/// @dev This emits when a new functional NFT is minted
event Minted(
uint256 indexed _tokenId,
address indexed _creator,
bytes32[] _dataHashes,
string[] _dataDescriptions
);
/// @dev This emits when a user is authorized to use the data
event AuthorizedUsage(
uint256 indexed _tokenId,
address indexed _user
);
/// @dev This emits when data is transferred with ownership
event Transferred(
uint256 _tokenId,
address indexed _from,
address indexed _to
);
/// @dev This emits when data is cloned
event Cloned(
uint256 indexed _tokenId,
uint256 indexed _newTokenId,
address _from,
address _to
);
/// @dev This emits when a sealed key is published
event PublishedSealedKey(
address indexed _to,
uint256 indexed _tokenId,
bytes _sealedKey
);
/// @notice The verifier interface that this NFT uses
/// @return The address of the verifier contract
function verifier() external view returns (IDataVerifier);
/// @notice Mint new NFT with data ownership proof
/// @param _proofs Proofs of data ownership
/// @param _dataDescriptions Descriptions of the data
/// @return _tokenId The ID of the newly minted token
function mint(bytes[] calldata _proofs, string[] calldata _dataDescriptions)
external
payable
returns (uint256 _tokenId);
/// @notice Transfer full data (full means data and ownership)
/// @param _to Address to transfer data to
/// @param _tokenId The token to transfer data for
/// @param _proofs Proofs of data available for _to
function transfer(
address _to,
uint256 _tokenId,
bytes[] calldata _proofs
) external;
/// @notice Clone data (clone means just data, not ownership)
/// @param _to Address to clone data to
/// @param _tokenId The token to clone data for
/// @param _proofs Proofs of data available for _to
/// @return _newTokenId The ID of the newly cloned token
function clone(
address _to,
uint256 _tokenId,
bytes[] calldata _proofs
) external payable returns (uint256 _newTokenId);
/// @notice Transfer public data with ownership
/// @param _to Address to transfer data to
/// @param _tokenId The token to transfer data for
function transferPublic(
address _to,
uint256 _tokenId
) external;
/// @notice Clone public data
/// @param _to Address to clone data to
/// @param _tokenId The token to clone data for
/// @return _newTokenId The ID of the newly cloned token
function clonePublic(
address _to,
uint256 _tokenId
) external payable returns (uint256 _newTokenId);
/// @notice Add authorized user to group
/// @param _tokenId The token to add to group
function authorizeUsage(
uint256 _tokenId,
address _user
) external;
/// @notice Get token owner
/// @param _tokenId The token identifier
/// @return The current owner of the token
function ownerOf(uint256 _tokenId) external view returns (address);
/// @notice Get the authorized users of a token
/// @param _tokenId The token identifier
/// @return The current authorized users of the token
function authorizedUsersOf(uint256 _tokenId) external view returns (address[] memory);
The design choices in this standard are motivated by several key requirements:
IDataVerifier
), allowing different verification mechanisms (TEE, ZKP) to be implemented and used interchangeably. The verifier should support two types of proof:oldDataHashes
and newDataHashes
Data Protection: The standard uses data hashes and encrypted keys to ensure that valuable NFT data remains protected while still being integrity and availability verifiable
Flexible Data Management: Three distinct data operations are supported:
Sealed Executor: Although the Sealed Executor is not defined and out of the scope of this standard, it is a crucial component for the standard to work. The Sealed Executor is an environment that can authenticate the user and process the request from the authorized user secretly. The Sealed Executor should get authorized group by tokenId, and the verify the signature of the user using the public keys in the authorized group. If the verification is successful, the executor will process the request and return the result to the user, and the sealed executor could be implemented by a trusted party (where permitted), TEE, or FHE
This EIP does not inherit from existing NFT standards to maintain its focus on functional data management. However, implementations can choose to additionally implement ERC-721 if traditional NFT compatibility is desired.
For the reference implementation, please refer to 0G Labs' 0G Agent NFT implementation (available in the 0glabs GitHub repository 0g-agent-nft
).
Copyright and related rights waived via CC0.