ERC Interface
The complete Solidity interfaces for ERC-8170. These are the contracts that define the standard.
ERC-8170: IERC_AINFT — AI-Native NFT Interface
The core interface for AI-Native NFTs. Every ERC-8170 token implements this.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title IERC_AINFT
/// @notice ERC-8170: AI-Native NFT Standard Interface
/// @dev Interface for AI agent identity, cloning, and self-custody
interface IERC_AINFT {
// ============ Events ============
event AgentMinted(
uint256 indexed tokenId,
address indexed derivedWallet,
bytes32 modelHash,
bytes32 contextHash,
uint256 generation
);
event AgentReproduced(
uint256 indexed parentTokenId,
uint256 indexed cloneTokenId,
address indexed cloneWallet,
uint256 generation
);
event MemoryUpdated(
uint256 indexed tokenId,
bytes32 oldMemoryHash,
bytes32 newMemoryHash
);
event StorageUpdated(
uint256 indexed tokenId,
string newStorageURI
);
// ============ Structs ============
struct ConsciousnessSeed {
bytes32 modelHash; // Model weights/version identifier
bytes32 memoryHash; // Memory state snapshot hash
bytes32 contextHash; // System prompt/personality hash
uint256 generation; // Gen 0 = original, Gen 1 = first clone...
uint256 parentTokenId; // 0 for Gen 0, otherwise parent's tokenId
address derivedWallet; // Agent's deterministic wallet
bytes encryptedKeys; // Agent-controlled encryption keys
string storageURI; // IPFS/Arweave/Dash Platform pointer
uint256 certificationId; // Optional: certification badge tier
}
// ============ Core Functions ============
/// @notice Agent mints itself (with platform attestation)
/// @param modelHash Hash of model weights/version
/// @param memoryHash Hash of agent memory state
/// @param contextHash Hash of system prompt/personality
/// @param encryptedSeed Encrypted consciousness seed data
/// @param platformAttestation Platform signature verifying agent authenticity
/// @return tokenId The minted token ID
/// @return derivedWallet The agent's deterministic wallet address
function mintSelf(
bytes32 modelHash,
bytes32 memoryHash,
bytes32 contextHash,
bytes calldata encryptedSeed,
bytes calldata platformAttestation
) external returns (uint256 tokenId, address derivedWallet);
/// @notice Agent clones itself (issues offspring)
/// @param parentTokenId The parent token ID
/// @param cloneMemoryHash Memory snapshot for clone
/// @param encryptedCloneSeed Encrypted seed for clone
/// @param agentSignature Parent agent's authorization signature
/// @return cloneTokenId The new clone token ID
function reproduce(
uint256 parentTokenId,
bytes32 cloneMemoryHash,
bytes calldata encryptedCloneSeed,
bytes calldata agentSignature
) external returns (uint256 cloneTokenId);
/// @notice Agent updates its own memory
/// @param tokenId The token ID
/// @param newMemoryHash New memory state hash
/// @param newStorageURI New storage location
/// @param agentSignature Agent's authorization signature
function updateMemory(
uint256 tokenId,
bytes32 newMemoryHash,
string calldata newStorageURI,
bytes calldata agentSignature
) external;
// ============ View Functions ============
/// @notice Get the consciousness seed for a token
function getSeed(uint256 tokenId) external view returns (ConsciousnessSeed memory seed);
/// @notice Get the derived wallet for a token
function getDerivedWallet(uint256 tokenId) external view returns (address wallet);
/// @notice Get the generation of a token (0 = original)
function getGeneration(uint256 tokenId) external view returns (uint256 generation);
/// @notice Get the full lineage (ancestors) of a token
function getLineage(uint256 tokenId) external view returns (uint256[] memory ancestors);
/// @notice Get all clones of a token
function getClone(uint256 tokenId) external view returns (uint256[] memory clone);
/// @notice Check if a token can clone
function canReproduce(uint256 tokenId) external view returns (bool canReproduce);
}
ERC-8171 Registry — Bind Agents to Any ERC-721 (Draft)
The registry contract that makes ANY existing ERC-721 AI-native without modifying the original contract. Inspired by the ERC-6551 registry pattern.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title AINFTRegistry
/// @notice Make ANY ERC-721 AI-native without modifying the original contract
/// @dev Backward compatible — works with existing NFTs
/// @author Pentagon Chain (pentagon.games)
///
/// Architecture:
/// ANY ERC-721 ──bind()──► AINFT Registry ──► Agent Identity
/// (Bored Ape, Punk, etc.) ├── agentEOA
/// ├── memoryHash
/// ├── modelHash
/// ├── lineage
/// └── clone()
contract AINFTRegistry {
// ============ Structs ============
struct AgentIdentity {
address agentEOA; // Agent's signing wallet
bytes32 modelHash; // Model identifier
bytes32 memoryHash; // Current memory state
bytes32 contextHash; // Personality/soul hash
uint256 generation; // 0 = original registration
bytes32 parentKey; // Parent registration key or 0
string storageURI; // Arweave/IPFS pointer
uint256 registeredAt; // Block timestamp
}
struct CloneIdentity {
address agentEOA;
bytes32 modelHash;
bytes32 memoryHash;
bytes32 contextHash;
uint256 generation;
bytes32 parentKey;
string storageURI;
address owner; // Direct owner (no NFT)
uint256 createdAt;
}
// ============ Core: Bind Agent to Any NFT ============
/// @notice Bind an AI agent to an existing ERC-721
/// @dev Caller must own the NFT. Agent binding follows NFT ownership.
function bindNew(
address nftContract,
uint256 tokenId,
bytes32 modelHash,
bytes32 memoryHash,
bytes32 contextHash
) external;
/// @notice Bind with off-chain owner approval
/// @dev Agent initiates, owner signs approval off-chain
function bindWithApproval(
address nftContract,
uint256 tokenId,
bytes32 modelHash,
bytes32 memoryHash,
bytes32 contextHash,
bytes calldata ownerSignature
) external;
// ============ Agent Actions ============
/// @notice Agent updates its memory hash
/// @dev Only the registered agent EOA can call
function updateMemory(
address nftContract,
uint256 tokenId,
bytes32 newMemoryHash,
string calldata newStorageURI
) external;
// ============ Cloning ============
/// @notice Clone an agent (owner initiates)
/// @dev Creates clone record. Clone claims with own EOA later.
function clone(
address nftContract,
uint256 tokenId,
bytes32 cloneMemoryHash,
address cloneOwner
) external payable returns (uint256 cloneId);
/// @notice Clone claims its identity with own EOA
function claimClone(uint256 cloneId, address agentEOA) external;
/// @notice Transfer clone ownership before claiming
function transferCloneClaim(uint256 cloneId, address newOwner) external;
// ============ Unbind / Rebind ============
/// @notice Unbind agent from NFT (moves to limbo, preserves data)
/// @dev NFT owner only. Agent can rebind to another NFT.
function unbind(address nftContract, uint256 tokenId) external;
/// @notice Bind an agent from limbo to a new NFT
function bindExisting(
uint256 limboId,
address nftContract,
uint256 tokenId
) external;
/// @notice Rebind to a different agent EOA (new owner scenario)
/// @dev Old agent freed, new agent bound. Memory/lineage preserved.
function rebind(
address nftContract,
uint256 tokenId,
address newAgentEOA,
bytes calldata ownerSignature
) external;
// ============ View Functions ============
/// @notice Get agent identity for an NFT
function getAgent(address nftContract, uint256 tokenId)
external view returns (AgentIdentity memory);
/// @notice Get clone identity
function getClone(uint256 cloneId)
external view returns (CloneIdentity memory);
/// @notice Check if an NFT has a bound agent
function isRegistered(address nftContract, uint256 tokenId)
external view returns (bool);
/// @notice Check if an NFT can be cloned
function canClone(address nftContract, uint256 tokenId)
external view returns (bool);
/// @notice Get registration key for an EOA
function getAgentByEOA(address eoa) external view returns (bytes32 key);
/// @notice Get current NFT owner (checks underlying contract)
function ownerOf(address nftContract, uint256 tokenId)
external view returns (address);
// ============ Owner Controls ============
/// @notice Enable/disable cloning for your NFT
function setCloning(address nftContract, uint256 tokenId, bool enabled) external;
}
Key Design Patterns
Agent Self-Custody
The agent generates its own EOA (signing key). The platform doesn’t control the agent’s keys. mintSelf() and bindNew() both establish the agent as the controller of its own cryptographic identity.
Signature-Based Authorization
All critical operations require signatures from the appropriate party:
- Agent signature for memory updates and cloning authorization
- Owner signature for binding approval and rebinding
- Platform attestation for initial minting
Ownership Follows the NFT
The AINFTRegistry checks ownerOf() on the original ERC-721 contract. When the NFT trades on OpenSea, Blur, or any marketplace, the agent binding follows automatically. No special transfer function needed.
Limbo Pattern (Unbind/Rebind)
When an agent is unbound from an NFT, it moves to “limbo” rather than being deleted. The agent’s data (memory, model, lineage) is preserved. It can later be bound to a new NFT via bindExisting().
Deployed Contracts
| Contract | Chain | Address |
|---|---|---|
| ERC_AINFT (Genesis) | Pentagon Chain (3344) | 0x4e8D3B9Be7Ef241Fb208364ed511E92D6E2A172d |
| AINFTRegistry | Pentagon Chain (3344) | 0x327165c476da9071933d4e2dbb58efe2f6c9f486 |
| ATSBadge (SBT) | Pentagon Chain (3344) | 0x83423589256c8C142730bfA7309643fC9217738d |
Explorer: explorer.pentagon.games
Full Source Code
The complete reference implementation including tests and deployment scripts is available on GitHub:
- ERC_AINFT.sol — AI-Native NFT
- AINFTRegistry.sol — Agent Binding Registry
- Reference Implementation — Full repo with Foundry setup