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.
Motivation
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:
Each agent is unique, with its own model, memory, and character
Agents have private metadata (e.g., neural network models, memory, character definitions) that defines their capabilities
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):
Has intrinsic value and is often the primary purpose of the transfer
Requires encrypted storage to protect intellectual property
Needs privacy-preserving and verifiable transfer mechanisms when ownership changes
For example, when transferring an agent NFT, we need to ensure:
The actual transfer of encrypted metadata (the agent’s model, memory, character, etc.) is verifiable
The new owner can securely access the metadata that constitutes the agent
The agent’s execution environment can verify ownership and load appropriate metadata
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.
Specification
The EIP defines three key interfaces: the main NFT interface, the metadata interface, and the data verification interface.
Data Verification System
The verification system consists of two core components that work together to ensure secure data operations:
On-chain Verifier (data verification interface)
Implemented as a smart contract
Verifies proofs submitted through contract calls
Returns structured verification results
Can be implemented using different verification mechanisms (TEE/ZKP)
Off-chain Prover
Generates proofs for ownership and availability claims
Works with encrypted data and keys
Implementation varies based on verification mechanism:
TEE-based: Generates proofs within trusted hardware
Proves knowledge of pre-images for claimed dataHashes
Verified on-chain through verifyOwnership()
Transfer Validity Proof
Generated by Prover for data transfers
Proves:
Knowledge of original data (pre-images)
Correct decryption and re-encryption of data
Secure key transmission (using receiver’s public key to encrypt the new key)
Data availability in storage (using receiver’s signature to confirm the data is available in storage)
Verified on-chain through 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:
TEE-based Implementation
Prover runs in trusted hardware
Can handle private keys securely
Enables direct data re-encryption
Verifier checks TEE attestations
ZKP-based Implementation
Prover generates cryptographic proofs
Cannot handle multi-party private keys
Re-encryption key known to prover
Requires additional re-encryption when next update, otherwise the new update is still visible to the prover
Data Verification Interface
/// @notice Output of ownership proof verification
structOwnershipProofOutput{bytes32[]dataHashes;boolisValid;}/// @notice Output of transfer validity proof verification
structTransferValidityProofOutput{bytes32[]oldDataHashes;bytes32[]newDataHashes;bytespubKey;bytessealedKey;boolisValid;}/// @notice Verify ownership of data
/// @param _proof Proof generated by companion prover system
/// @return Verification result and validated data hashes
functionverifyOwnership(bytescalldata_proof)externalviewreturns(OwnershipProofOutputmemory);/// @notice Verify data transfer validity
/// @param _proof Proof generated by companion prover system
/// @return Verification result and transfer details
functionverifyTransferValidity(bytescalldata_proof)externalviewreturns(TransferValidityProofOutputmemory);
Metadata Interface
/// @dev This emits when data is updated
eventUpdated(uint256indexed_tokenId,bytes32[]_oldDataHashes,bytes32[]_newDataHashes);/// @notice Get the name of the NFT collection
functionname()externalviewreturns(stringmemory);/// @notice Get the symbol of the NFT collection
functionsymbol()externalviewreturns(stringmemory);/// @notice Get the metadata URI for a specific token
functiontokenURI(uint256tokenId)externalviewreturns(stringmemory);/// @notice Update data
/// @param _tokenId The token to update
/// @param _proofs Proof of updated data ownership
functionupdate(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
functiondataHashesOf(uint256_tokenId)publicviewreturns(bytes32[]memory);/// @notice Get the data description of a token
/// @param _tokenId The token identifier
/// @return The current data description of the token
functiondataDescriptionsOf(uint256_tokenId)publicviewreturns(string[]memory);
Main NFT Interface
/// @dev This emits when a new functional NFT is minted
eventMinted(uint256indexed_tokenId,addressindexed_creator,bytes32[]_dataHashes,string[]_dataDescriptions);/// @dev This emits when a user is authorized to use the data
eventAuthorizedUsage(uint256indexed_tokenId,addressindexed_user);/// @dev This emits when data is transferred with ownership
eventTransferred(uint256_tokenId,addressindexed_from,addressindexed_to);/// @dev This emits when data is cloned
eventCloned(uint256indexed_tokenId,uint256indexed_newTokenId,address_from,address_to);/// @dev This emits when a sealed key is published
eventPublishedSealedKey(addressindexed_to,uint256indexed_tokenId,bytes_sealedKey);/// @notice The verifier interface that this NFT uses
/// @return The address of the verifier contract
functionverifier()externalviewreturns(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
functionmint(bytes[]calldata_proofs,string[]calldata_dataDescriptions)externalpayablereturns(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
functiontransfer(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
functionclone(address_to,uint256_tokenId,bytes[]calldata_proofs)externalpayablereturns(uint256_newTokenId);/// @notice Transfer public data with ownership
/// @param _to Address to transfer data to
/// @param _tokenId The token to transfer data for
functiontransferPublic(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
functionclonePublic(address_to,uint256_tokenId)externalpayablereturns(uint256_newTokenId);/// @notice Add authorized user to group
/// @param _tokenId The token to add to group
functionauthorizeUsage(uint256_tokenId,address_user)external;/// @notice Get token owner
/// @param _tokenId The token identifier
/// @return The current owner of the token
functionownerOf(uint256_tokenId)externalviewreturns(address);/// @notice Get the authorized users of a token
/// @param _tokenId The token identifier
/// @return The current authorized users of the token
functionauthorizedUsersOf(uint256_tokenId)externalviewreturns(address[]memory);
Rationale
The design choices in this standard are motivated by several key requirements:
Verification Abstraction: The standard separates the verification logic into a dedicated interface (IDataVerifier), allowing different verification mechanisms (TEE, ZKP) to be implemented and used interchangeably. The verifier should support two types of proof:
Ownership Proof Verifies that the prover possesses the original data by demonstrating knowledge of the pre-images that generate the claimed dataHashes
Transfer Validity Proof Verifies secure data integrity and availability by proving: knowledge of the original data (pre-images of oldDataHashes); ability to decrypt with oldKey and re-encrypt with newKey; secure transmission of newKey using recipient’s public key; integrity of the newly encrypted data matching newDataHashes; and data availability confirmed by recipient’s signature on both 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:
Full transfer, where the data and ownership are transferred to the new owner
Data cloning, where the data is cloned to a new token but the ownership is not transferred
Data usage authorization, where the data is authorized to be used by a specific user, but the ownership is not transferred, and the user still cannot access the data. This need an environment to authenticate the user and process the request from the authorized user secretly, we call it “Sealed Executor”
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
Backwards Compatibility
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.
Reference Implementation
For the reference implementation, please refer to 0G Labs’ 0G Agent NFT implementation (available in the 0glabs GitHub repository 0g-agent-nft).
Security Considerations
Proof Verification
Implementations must carefully verify all assertions in the proof
Replay attacks must be prevented
Different verification systems have their own security considerations, and distinct capabilities regarding key management: TEE can securely handle private keys from multi-parties, enabling direct data re-encryption. However, ZKP, due to its cryptographic nature, cannot process private keys from multi-parties. As a result, the re-encryption key is also from the prover (i.e., the sender), so tokens acquired through transfer or cloning must undergo re-encryption during their next update, otherwise the new update is still visible to the previous owner. This distinction in key handling capabilities affects how data transformations are managed during later usage
Data Privacy
Only hashes and sealed keys are stored on-chain, actual functional data must be stored and transmitted securely off-chain
Key management is crucial for secure data access
TEE verification system could support private key of the receiver, but ZKP verification system could not. So when using ZKP, the token transferred or cloned from other should be re-encrypted when next update, otherwise the new update is still visible to the previous owner
Access Control and State Management
Operations restricted to token owners only
All data operations must maintain integrity and availability
Critical state changes (sealed keys, ownership, permissions) must be atomic and verifiable
Sealed Executor
Although out of scope for this standard, the Sealed Executor is crucial for secure operation
The Sealed Executor authenticates users and processes requests in a secure environment by verifying user signatures against authorized public keys for each tokenId
The Sealed Executor can be implemented through a trusted party (where permitted), Trusted Execution Environment (TEE), or Fully Homomorphic Encryption (FHE)
Ensuring secure request processing and result delivery
Ming Wu (@sparkmiw), Jason Zeng (@zenghbo), Wei Wu (@Wilbert957), Michael Heinrich (@michaelomg), "ERC-7857: AI Agents NFT with Private Metadata [DRAFT]," Ethereum Improvement Proposals, no. 7857, January 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7857.