-
Notifications
You must be signed in to change notification settings - Fork 491
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ERC: AI Agent NFTs #348
Merged
eip-review-bot
merged 21 commits into
ethereum:master
from
marleymarl:erc-ai-agent-nfts-drafting
Oct 14, 2024
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
70dacf3
Initial draft of AI Agent NFTs standard
7e6b555
added specifications
08a0600
fixed typos
ccbad95
removed dot link
8f4f2a3
added discussion link from EM
c6c3d5e
fixed link
d1a3c5a
rename to erc-7661
a357979
updated erc721 links
f6f5f5b
removed custom sections and added eip line:
d31e846
change 721 link to eip
b1a9940
changed filename to erc-7662. (Apologies, the PR green checkmark seek…
fc374b5
fixed typo on github handle
ecaaf62
added reference implementation, added bool promptsEncrypted to Agent …
677a955
Update ERCS/erc-7662.md
marleymarl 84075fd
Update ERCS/erc-7662.md
marleymarl e97a7a7
created assets/erc-7662 folder with contract
d4a18fe
updated file link
b465bf3
added more detail regarding goal of standard
36ecc63
removed ref requiring link
0c2cbdd
removed external links, changed struct to interface, removed function…
7cd0b0d
revert to ERC-XXXX
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
--- | ||
eip: 7662 | ||
title: AI Agent NFTs | ||
description: A specification for NFTs that represent AI Agents. | ||
author: Greg Marlin (@marleymarl) | ||
discussions-to: https://ethereum-magicians.org/t/erc-7662-ai-agent-nfts/19371 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2024-03-26 | ||
requires: 721 | ||
--- | ||
|
||
## Abstract | ||
|
||
This proposal introduces a standard for AI agent NFTs. When AI Agents are created and traded as NFTs, it doesn't make sense to put the prompts in the token metadata, therefore it requires a standard custom struct. It also doesn't make sense to store the prompts directly onchain as they can be quite large, therefore this standard proposes they be stored as decentralized storage URLs. This standard also proposes two options on how this data should be made private to the owner of the NFT, with the favored implementation option being encrypting the data using custom contract parameters for decryption that decrypt only to the owner of the NFT. | ||
|
||
## Motivation | ||
|
||
The creation and trading of AI Agent NFTs are a natural fit and offer the potential for an entirely new onchain market. This requires some custom data to be embedded in the NFT through a custom struct and this needs to be standardized so that any marketplace or AI Agent management product, among others, know how to create and parse AI Agent NFTs. The goal of this standard is to provide a new utility for NFTs in the field of AI and also to provide new liquidity, through the NFT market, for AI Agents. If widely adopted by marketplaces, and infrastructure and no-code providers this should open up a new market and community for AI Agent creators in different fields, AI Agent consumers and 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. | ||
|
||
|
||
All ERC-XXXX compliant contracts MUST implement the standard [ERC-721](./eip-721.md) functionality for minting and transferring NFTs, and MUST additionally implement this standard's Agent interface | ||
|
||
```solidity | ||
|
||
interface IERC7662 is IERC721 { | ||
|
||
function getAgentData(uint256 tokenId) external view returns ( | ||
string memory name, | ||
string memory description, | ||
string memory model, | ||
string memory userPromptURI, | ||
string memory systemPromptURI, | ||
bool promptsEncrypted | ||
); | ||
|
||
event AgentUpdated(uint256 indexed tokenId); | ||
} | ||
``` | ||
|
||
and MUST implement the mapping between NFT Token ID and its Agent information. | ||
|
||
It is RECOMMENDED that this mapping is public and that the URIs for User Prompt and System Prompt are made private through encryption with decryption logic set to the holder of the NFT via custom contract parameters set during encryption, and the method or platform used to provide this encryption SHOULD be retrievable as a data property of the NFT in order that platforms that should facilitate the use of these NFTs can set up a predictable way to handle this decryption, depending on the platform or method used. | ||
|
||
It is conceivable to also create an implementation whereby this mapping was set to private and accessed through a custom function that restricted access to the holder of the NFT. This approach would explose the prompts through their urls though, therefore the RECOMMENDED approach is a public mapping and encryption on the URLs. This also has the benefit of publicly exposing the data in the Agent struct to verify name, description and model and that encyrpted URIs for the User Prompt and System Prompt exist. | ||
|
||
All ERC-XXXX compliant contracts MUST implement a function to mint new Agent tokens. This function SHOULD: | ||
|
||
- Accept parameters for all Agent properties (name, description, model, userPromptURI, systemPromptURI, etc.) | ||
- Mint a new token to the specified recipient | ||
- Associate the provided Agent properties with the newly minted token | ||
- Emit an event signaling the creation of a new Agent token | ||
|
||
It is RECOMMENDED that ERC-XXXX compliant contracts provide functionality to encrypt the user prompt and system prompt. This functionality SHOULD: | ||
|
||
- Allow only the token owner to encrypt the prompts | ||
- Update the userPromptURI and systemPromptURI with encrypted versions | ||
- Set a flag indicating that the prompts are encrypted | ||
|
||
It is RECOMMENDED to implement the following event: | ||
|
||
```solidity | ||
event AgentCreated(string name, string description, string model, address recipient, uint256 tokenId) | ||
|
||
``` | ||
|
||
This event SHOULD be emitted when a new Agent token is minted, providing key information about the newly created Agent. | ||
|
||
To enable dynamic variables being injected into the User Prompt before being run, any such variables MUST be surrounded with ${} e.g. ${dynamicVariableName} in order that they can be recognized and handled appropriately by programs and systems that will enabled the injection, e.g. web forms and automation systems. | ||
|
||
It is RECOMMENDED to add a data to the [ERC-721](./eip-721.md) standard that makes it easy for e.g. NFT Marketplaces to display data about the AI Agent NFT, i.e. Model, which in turn reveals the platform that is used for the agent, e.g. OpenAI in the case of gpt-4-0125-preview or Anthropic in the case of claude-3-opus-20240229. The standard name and description can be used to display the Agent Name and Agent Description. | ||
|
||
## Rationale | ||
|
||
This standard provides a unified way to create and parse AI Agent NFTs. | ||
|
||
This standard codifies the necessary parameters of Name, Description, Model, User Prompt, and System Prompt for creating and using AI Agent NFTs. | ||
|
||
It doesn't make practical sense to store the user and system prompts in an existing [ERC-721](./eip-721.md) as the only place to put would be in the token metadata that is open for anyone to access the prompts without owning the NFT. By storing the prompts in a custom Agent struct and restricting access to the prompts to the holder of the NFT. One way to do this would be through restricing access to the struct info to the holder of the NFT through a custom function, however since that option still exposes the prompt URIs to the public and thus the data inside them, the recommended method is by encrypting the prompts onchain and tying the decryption of the URLs to the holder of the NFT, using onchain services that enable decryption to be tied to contract parameters such as ownerOf(tokenId). | ||
|
||
|
||
## Backwards Compatibility | ||
|
||
The AI Agents NFT standard introduces additional features and data to the standard [ERC-721](./eip-721.md) protocol, aimed at addressing the practical requirements of using NFTs to store, trade and use AI Agents. It is designed to be fully backward-compatible with the original [ERC-721](./eip-721.md) standard. All existing [ERC-721](./eip-721.md) functions (such as transferFrom, approve, and balanceOf) retain their original functionality and interfaces. Our extension does not modify these core behaviors, ensuring that any [ERC-721](./eip-721.md) compliant wallet or service can interact with these tokens without modifications. | ||
|
||
### Reference Implementation | ||
|
||
This is being currently implemented in a product for creating, managing and using AI Agents Onchain through a DApp interface. In this implementation, an encryption platform is being used to encrypt the prompts using custom EVMContractParameters that only decrypt for the holder of the NFT and using a decentralized storage network to store the URLs of this encrypted data. To facilitate that and make DApp handling easier, some parameters were added to Agent and the addEncryptedPrompts function is added that enables adding the encrypted prompt URIs after first minting the NFT (as the tokenId of the NFT is needed for setting the encryption/decryption conditions). | ||
|
||
A reference smart contract is provided in the assets folder. | ||
|
||
|
||
|
||
## Security Considerations | ||
|
||
marleymarl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<!-- TODO --> | ||
Check warning on line 102 in ERCS/erc-7662.md GitHub Actions / EIP WalidatorHTML comments are only allowed while `status` is one of: `Draft`, `Withdrawn`
|
||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | ||
import "@openzeppelin/contracts/interfaces/IERC721.sol"; | ||
import "./lib/FactoryOperatorable.sol"; | ||
|
||
contract ERC7662 is FactoryOperatorable, ERC721URIStorage { | ||
|
||
uint256 public tokenIds; | ||
|
||
//NFT Base URI | ||
string public baseURI; | ||
|
||
|
||
struct Agent { | ||
string name; | ||
string description; | ||
string model; | ||
string userPromptURI; | ||
string systemPromptURI; | ||
string imageURI; | ||
string category; | ||
bool promptsEncrypted; | ||
} | ||
|
||
mapping(address => uint256[]) public collectionIds; | ||
mapping(uint => Agent) public Agents; | ||
|
||
event AgentCreated(string name, string description, string model, string category, address recipient, uint256 tokenId); | ||
|
||
constructor( | ||
string memory collectionBaseURI, | ||
address admin, | ||
address operator) ERC721("Agent NFTs", "AGENTS") FactoryOperatorable(admin, operator) { | ||
|
||
baseURI = collectionBaseURI; | ||
|
||
} | ||
|
||
/** | ||
* @dev Override supportInterface. | ||
*/ | ||
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721) returns (bool) { | ||
return super.supportsInterface(interfaceId); | ||
} | ||
|
||
|
||
/** | ||
* @dev Mint an Agent NFT and attach its data to the token id | ||
* | ||
* @param _recipient address to receive NFT | ||
* @param _name string Name of the Agent | ||
* @param _description string Description of the Agent | ||
* @param _model string AI Model of the Agent | ||
* @param _userPromptURI string URI of the Agent's User Prompt | ||
* @param _systemPromptURI string URI of the Agent's System Prompt | ||
* @param _imageURI string URI of the NFT image | ||
* @param _category string Category of Agent | ||
* @param _tokenURI string URI of the NFT | ||
* | ||
* Emits an AgentCreated event. | ||
*/ | ||
function mintAgent(address _recipient, string memory _name, string memory _description, string memory _model, string memory _userPromptURI, string memory _systemPromptURI, string memory _imageURI, string memory _category, string memory _tokenURI) public { | ||
tokenIds++; | ||
bool _promptsEncrypted = false; | ||
Agents[tokenIds] = Agent(_name, _description, _model, _userPromptURI, _systemPromptURI, _imageURI, _category, _promptsEncrypted); | ||
|
||
_mint(_recipient, tokenIds); | ||
collectionIds[_recipient].push(tokenIds); | ||
_setTokenURI(tokenIds, _tokenURI); | ||
emit AgentCreated(_name, _description, _model, _category, _recipient, tokenIds); | ||
} | ||
|
||
/** | ||
* @dev Update NFT with Encrypted Prompts as token id needed first for encryption params | ||
* | ||
* @param _tokenId uint256 Id of the NFT to update | ||
* @param _encryptedUserPromptURI string Encrypted URI of the Agent's User Prompt | ||
* @param _encryptedSystemPromptURI string Encrypted URI of the Agent's System Prompt | ||
*/ | ||
function addEncryptedPrompts(uint256 _tokenId, string memory _encryptedUserPromptURI, string memory _encryptedSystemPromptURI) public { | ||
require(ownerOf(_tokenId) == msg.sender, "Sender must be token owner"); | ||
Agent storage agent = Agents[_tokenId]; | ||
agent.userPromptURI = _encryptedUserPromptURI; | ||
agent.systemPromptURI = _encryptedSystemPromptURI; | ||
agent.promptsEncrypted = true; | ||
} | ||
|
||
/** | ||
* @dev Return base URI | ||
* Override {ERC721:_baseURI} | ||
*/ | ||
function _baseURI() internal view override returns (string memory) { | ||
return baseURI; | ||
} | ||
|
||
/** | ||
* @dev Return all token ids owned by address | ||
* @param _address address Address to check for | ||
*/ | ||
function getCollectionIds(address _address) public view returns (uint256[] memory) { | ||
return collectionIds[_address]; | ||
} | ||
|
||
|
||
/** | ||
* @dev Remove the given token from collectionIds. | ||
* | ||
* @param from address from | ||
* @param tokenId tokenId to remove | ||
*/ | ||
function _popId(address from, uint256 tokenId) internal { | ||
uint256[] storage _collectionIds = collectionIds[from]; | ||
for (uint256 i = 0; i < _collectionIds.length; i++) { | ||
if (_collectionIds[i] == tokenId) { | ||
if (i != _collectionIds.length - 1) { | ||
_collectionIds[i] = _collectionIds[_collectionIds.length - 1]; | ||
} | ||
_collectionIds.pop(); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @dev Transfers `tokenId` from `from` to `to`. | ||
* | ||
* Requirements: | ||
* | ||
* - `tokenId` token must be owned by `from`. | ||
* | ||
* @param from address from | ||
* @param to address to | ||
* @param tokenId tokenId to transfer | ||
*/ | ||
function _transfer( | ||
address from, | ||
address to, | ||
uint256 tokenId | ||
) internal override { | ||
super._transfer(from, to, tokenId); | ||
_popId(from, tokenId); | ||
collectionIds[to].push(tokenId); | ||
} | ||
|
||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your description doesn't include any new information that wasn't in your title, and it has a bit of fluff ("A specification for".) You should use the description to elaborate on the ideas introduced in the title as succinctly as possible.
For example, what is an AI Agent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point - will add, thanks.