Skip to content

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.

function burn(uint256 tokenId) external onlyOwner

Parameters: - tokenId: ID of token to burn

Events: AgentDeregistered(tokenId)

setTokenURI(uint256 tokenId, string newURI)#

Update agent metadata URI.

function setTokenURI(
    uint256 tokenId,
    string calldata newURI
) external onlyOwnerOrTrainer

Parameters: - tokenId: ID of token to update - newURI: New metadata URI

Trainer Management#

addTrainer(address trainer)#

Grant trainer privileges to address.

function addTrainer(address trainer) external onlyOwner

Parameters: - trainer: Address to add as trainer

Events: TrainerAdded(trainer)

removeTrainer(address trainer)#

Revoke trainer privileges from address.

function removeTrainer(address trainer) external onlyOwner

Parameters: - trainer: Address to remove as trainer

Events: TrainerRemoved(trainer)

isTrainer(address trainer)#

Check if address has trainer privileges.

function isTrainer(address trainer) public view returns (bool)

Parameters: - trainer: Address to check

Returns: Boolean indicating trainer status

Utility Functions#

getTokenUris(uint256[] tokenIds)#

Get multiple token URIs in single call.

function getTokenUris(uint256[] calldata tokenIds) 
    external view returns (string[] memory)

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#

make deploy-agent-registry NETWORK=base-sepolia

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#

  1. Metadata Validation: Validate metadata structure before setting URIs
  2. Trainer Management: Regularly review trainer permissions
  3. URI Immutability: Use content-addressed storage (IPFS) for metadata
  4. 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)