AgentRegistry Documentation#
The AgentRegistry is an ERC-721 NFT contract designed for registering AI agents on-chain. Each agent is represented as a unique NFT with metadata stored off-chain (typically IPFS), providing a decentralized registry for agent identity and management.
Overview#
The AgentRegistry contract serves as the central registry for AI agents, where each agent is represented as an NFT with:
- ERC-721 Compliance: Standard NFT functionality with metadata URI support
- Simplified Permissions: Owner-based control with trainer delegation
- Metadata-First Approach: All agent data stored in metadata (no duplicate on-chain storage)
- Trainer System: Address-based trainer permissions for operational flexibility
- Gas Optimized: Clean, minimal storage design
Contract Architecture#
graph TB
A[AgentRegistry Contract] --> B[ERC-721 Base]
A --> C[ERC721URIStorage]
A --> D[Ownable]
A --> E[Agent Registration]
A --> F[Trainer Management]
A --> G[Metadata Management]
E --> E1[Mint Agent NFTs]
E --> E2[Burn Agent NFTs]
E --> E3[IPFS Metadata]
F --> F1[Add Trainers]
F --> F2[Remove Trainers]
F --> F3[Check Trainer Status]
G --> G1[Set Token URIs]
G --> G2[Batch URI Queries]
G --> G3[Metadata Updates]
style A fill:#1e3a8a,stroke:#3b82f6,stroke-width:3px,color:#fff
style E fill:#059669,stroke:#10b981,stroke-width:2px,color:#fff
style F fill:#ea580c,stroke:#f97316,stroke-width:2px,color:#fff
style G fill:#7c3aed,stroke:#a855f7,stroke-width:2px,color:#fff
Contract Details#
Property | Value |
---|---|
Contract Name | AgentRegistry |
Token Symbol | AGENT |
Standard | ERC-721 with ERC721URIStorage |
Deployment Address | See deployment logs |
Owner Address | 0x5D6D8518A1d564c85ea5c41d1dc0deca70F2301C |
Key Features#
✨ Agent Registration#
- ERC-721 Compliant: Standard NFT functionality with metadata URI support
- Simplified Permissions: Owner-based control with trainer delegation
- Metadata-First: All agent data stored in metadata (no duplicate on-chain storage)
👥 Trainer System#
- Address-based Permissions: Flexible trainer management system
- Limited Access: Trainers can update metadata but cannot mint/burn
- Operational Flexibility: Multiple trainers for distributed management
🔧 Gas Optimization#
- Clean Storage: Minimal on-chain data storage
- Efficient Operations: Optimized for common use cases
- Batch Operations: Multiple token URI queries in single call
Permission Model#
flowchart TD
A["Owner"] --> B["Full Administrative Control"]
B --> B1["Mint Agent NFTs"]
B --> B2["Burn Agent NFTs"]
B --> B3["Add/Remove Trainers"]
B --> B4["Update Metadata URIs"]
C["Trainers"] --> D["Limited Operational Access"]
D --> D1["Update Metadata URIs"]
D --> D2["Cannot Mint/Burn"]
D --> D3["Cannot Manage Trainers"]
E["Public"] --> F["Read-Only Access"]
F --> F1["View Token Information"]
F --> F2["Check Trainer Status"]
F --> F3["Standard ERC-721 Views"]
style A fill:#1e3a8a,stroke:#3b82f6,stroke-width:2px,color:#fff
style C fill:#059669,stroke:#10b981,stroke-width:2px,color:#fff
style E fill:#ea580c,stroke:#f97316,stroke-width:2px,color:#fff
style B fill:#7c3aed,stroke:#a855f7,stroke-width:2px,color:#fff
style D fill:#7c3aed,stroke:#a855f7,stroke-width:2px,color:#fff
style F fill:#7c3aed,stroke:#a855f7,stroke-width:2px,color:#fff
Core Functions#
Agent Management#
register(address recipient, string metadataURI)
#
Mint new agent NFT.
function register(
address recipient,
string calldata metadataURI
) external onlyOwner returns (uint256)
Parameters:
- recipient
: Address to receive the NFT
- metadataURI
: IPFS URI containing agent metadata
Returns: Token ID of newly minted NFT
Events: AgentRegistered(tokenId, owner, metadataURI)
burn(uint256 tokenId)
#
Permanently remove agent NFT.
Parameters:
- tokenId
: ID of token to burn
Events: AgentDeregistered(tokenId)
setTokenURI(uint256 tokenId, string newURI)
#
Update agent metadata URI.
Parameters:
- tokenId
: ID of token to update
- newURI
: New metadata URI
Trainer Management#
addTrainer(address trainer)
#
Grant trainer privileges to address.
Parameters:
- trainer
: Address to add as trainer
Events: TrainerAdded(trainer)
removeTrainer(address trainer)
#
Revoke trainer privileges from address.
Parameters:
- trainer
: Address to remove as trainer
Events: TrainerRemoved(trainer)
isTrainer(address trainer)
#
Check if address has trainer privileges.
Parameters:
- trainer
: Address to check
Returns: Boolean indicating trainer status
Utility Functions#
getTokenUris(uint256[] tokenIds)
#
Get multiple token URIs in single call.
Parameters:
- tokenIds
: Array of token IDs
Returns: Array of corresponding metadata URIs
Events#
event AgentRegistered(
uint256 indexed tokenId,
address indexed owner,
string metadataURI
);
event AgentDeregistered(uint256 indexed tokenId);
event TrainerAdded(address indexed trainer);
event TrainerRemoved(address indexed trainer);
Error Handling#
The contract includes custom errors for gas-efficient revert reasons:
Error | Description |
---|---|
InvalidRecipient() |
Zero address provided as recipient |
InvalidTokenId() |
Token does not exist |
UnauthorizedCaller() |
Caller lacks required permissions |
InvalidMetadataURI() |
Empty metadata URI provided |
TrainerAlreadyAdded() |
Address already has trainer privileges |
TrainerNotFound() |
Address is not a trainer |
InvalidTrainerAddress() |
Zero address provided as trainer |
Metadata Structure#
Agent metadata should follow this JSON structure:
{
"name": "Agent Name",
"description": "Agent description",
"image": "ipfs://...",
"agentId": "unique-agent-identifier",
"applicationStatus": "active|pending|suspended",
"attributes": [
{
"trait_type": "Agent Type",
"value": "AI Assistant"
},
{
"trait_type": "Version",
"value": "1.0.0"
}
],
"external_url": "https://agent-dashboard.com/agent-id"
}
Deployment#
Constructor Parameters#
constructor(
string memory _name, // Collection name (e.g., "Agent Registry")
string memory _symbol, // Collection symbol (e.g., "AGENT")
address _owner // Owner address
)
Deployment Example#
// Using Hardhat Ignition
const agentRegistry = m.contract("AgentRegistry", [
"Agent Registry", // name
"AGENT", // symbol
"0x5D6D8518A1d564c85ea5c41d1dc0deca70F2301C" // owner
]);
Makefile Deployment#
Usage Patterns#
Basic Agent Registration#
// Owner registers new agent
uint256 tokenId = agentRegistry.register(
userAddress,
"ipfs://QmHash.../agent-metadata.json"
);
Trainer Management#
// Owner adds trainer
agentRegistry.addTrainer(trainerAddress);
// Trainer updates metadata
agentRegistry.setTokenURI(tokenId, "ipfs://newHash.../updated-metadata.json");
// Owner removes trainer
agentRegistry.removeTrainer(trainerAddress);
Query Operations#
// Check trainer status
bool isTrainerActive = agentRegistry.isTrainer(someAddress);
// Get multiple metadata URIs
uint256[] memory tokenIds = [1, 2, 3];
string[] memory uris = agentRegistry.getTokenUris(tokenIds);
// Standard ERC-721 queries
address owner = agentRegistry.ownerOf(tokenId);
string memory uri = agentRegistry.tokenURI(tokenId);
Security Considerations#
Access Control#
- Owner Centralization: Single owner has full control over the registry
- Trainer Limitations: Trainers cannot burn tokens or manage other trainers
- Metadata Integrity: Metadata URIs should be immutable (IPFS recommended)
Best Practices#
- Metadata Validation: Validate metadata structure before setting URIs
- Trainer Management: Regularly review trainer permissions
- URI Immutability: Use content-addressed storage (IPFS) for metadata
- Event Monitoring: Monitor events for unauthorized changes
Integration Examples#
Frontend Integration#
// Connect to contract
const agentRegistry = new ethers.Contract(address, abi, signer);
// Register new agent
const tx = await agentRegistry.register(
recipientAddress,
metadataURI
);
await tx.wait();
// Listen for registrations
agentRegistry.on("AgentRegistered", (tokenId, owner, metadataURI) => {
console.log(`New agent ${tokenId} registered for ${owner}`);
});
Backend Integration#
// Query agent data
const tokenId = 1;
const owner = await agentRegistry.ownerOf(tokenId);
const metadataURI = await agentRegistry.tokenURI(tokenId);
const metadata = await fetch(metadataURI).then(r => r.json());
console.log(`Agent ${metadata.agentId} owned by ${owner}`);
Gas Costs (Estimated)#
Function | Estimated Gas |
---|---|
register() |
~100,000 gas |
burn() |
~50,000 gas |
setTokenURI() |
~30,000 gas |
addTrainer() |
~25,000 gas |
removeTrainer() |
~25,000 gas |
View functions | <10,000 gas |
Changelog#
v2.0.0 (Current)#
- Renamed from SpiritRegistry to AgentRegistry
- Removed on-chain agentId and applicationStatus storage
- Simplified permission system (removed AccessControl)
- Implemented address-based trainer system
- Removed TrainerRegistry dependency
v1.0.0 (Legacy)#
- Initial SpiritRegistry implementation
- Complex role-based permissions
- On-chain agent data storage
- TrainerRegistry integration
Support#
For technical support or questions about the AgentRegistry contract, please refer to:
- Contract source code in /contracts/SuperTokens/AgentRegistry.sol
- Deployment scripts in /ignition/modules/SuperTokens/DeployAgentRegistry.ts
- Test files in /test/SpiritRegistry/
(being updated to AgentRegistry)