Primary Agent

Overview

The Primary Agent Registry is a singleton on-chain registry that links each Ethereum address to a single agent identity, enabling any address to be resolved to the agent it represents. It implements the ERC-8160 standard and works with ERC-8004 agent registries and ERC-8122 for cross-chain agent account discovery. It is deployed once per chain as a single authoritative source for agent resolution.

Agent IDs are packed into a compact byte sequence for efficient storage and transport:

Packed Encoding
20 bytes: registry address | 1 byte: ID length | N bytes: token ID

Given any Ethereum address, you can resolve the agent it represents with a single call:

Solidity
(address registry, uint256 tokenId) = primaryAgentRegistry.resolveAgentId(someAddress);

Standards

The Primary Agent Registry is built on three complementary ERC standards that together provide a complete agent identity layer for Ethereum.

ERC-8004: Agent Registry

Defines the NFT-based agent identity registry interface. Each agent is represented as an NFT in an ERC-8004 compliant registry, providing a standard way to create, manage, and query agent identities on-chain.

EIP-8004 ↗

ERC-8122: Destination-Chain Agent-Owned Account Discovery

Enables cross-chain agent account discovery. Given an agent identity on one chain, ERC-8122 provides a standard mechanism to discover the accounts that agent controls on other destination chains.

EIP-8122 ↗

ERC-8160: Primary Agent Registry (Draft)

Defines the singleton registry standard that maps Ethereum addresses to their agent identities. This is the standard that the Primary Agent Registry implements. ERC-8160 provides a single authoritative source per chain for resolving any address to its agent, using pluggable registrars for verification.

ERC-8160 ↗

Architecture

The registry uses a hub-and-spoke architecture with a central PrimaryAgentRegistry and pluggable registrar contracts. The registry itself stores the mappings, while registrars handle verification logic for different account types.

PrimaryAgentRegistry

Central hub — stores address-to-agent mappings and delegates verification to registrars

  • SelfRegistrar

    EOAs register themselves directly

  • ERC1271Registrar

    Smart-contract wallets via ERC-1271 signature validation

  • OwnableRegistrar

    Ownable contracts registered by their owner

  • AccessControlRegistrar

    AccessControl contracts registered by an admin role

  • SignedRegistrar

    Off-chain signature-based registration with replay protection

Registrars

Each registrar implements a different verification strategy, allowing the registry to support a wide range of account types.

RegistrarUse CaseVerification
SelfRegistrarEOA self-registrationmsg.sender == target address
ERC1271RegistrarSmart-contract wallets (e.g. Safe, ERC-4337)ERC-1271 isValidSignature check
OwnableRegistrarOwnable contractsCaller is owner() of target contract
AccessControlRegistrarAccessControl contractsCaller holds DEFAULT_ADMIN_ROLE on target
SignedRegistrarOff-chain / gasless registrationEIP-712 typed signature with nonce replay protection

Usage Examples

Register an EOA

An externally-owned account can register itself via the SelfRegistrar:

Solidity
// The caller registers their own address
selfRegistrar.register(
    agentRegistry,   // address of the agent NFT registry
    tokenId          // the token ID representing the agent
);

Register via Signature

For gasless or delegated registration, use the SignedRegistrar with an EIP-712 typed signature:

Solidity
// A relayer submits the registration on behalf of the signer
signedRegistrar.register(
    account,         // address to register
    agentRegistry,   // address of the agent NFT registry
    tokenId,         // the token ID representing the agent
    deadline,        // signature expiration timestamp
    signature        // EIP-712 signature from the account holder
);

Resolve an Address

Given any Ethereum address, resolve the agent identity it is linked to:

Solidity
(address registry, uint256 tokenId) = primaryAgentRegistry.resolveAgentId(
    someAddress
);

// registry == address(0) means no agent is registered
require(registry != address(0), "No agent registered");

Contract Addresses

Sepolia

Base

Storage Encoding

The registry packs each registration into a single storage slot for gas efficiency. The agent ID is encoded as a byte sequence containing the registry address, an ID-length byte, and the token ID.

FieldBytesDescription
Registry Address20The address of the agent NFT registry contract
ID Length1Length of the token ID in bytes (1–12)
Token ID1–12Big-endian encoded token ID, trimmed to minimal length

This encoding fits within a single 32-byte storage slot for token IDs up to 12 bytes (covering IDs up to ~79 billion billion), keeping registration and resolution to a single SLOAD/SSTORE.

Example
// Token ID 42 with registry at 0xABCD...1234
// Encoded: 0xABCD...1234  |  01  |  2A
//          (20 bytes)       (1)    (1 byte for value 42)

// Token ID 100000 (0x0186A0) with same registry
// Encoded: 0xABCD...1234  |  03  |  01 86 A0
//          (20 bytes)       (1)    (3 bytes)