ERC-8004's third registry is live and empty
ERC-8004 ships three registries: identity, reputation, validation. On Ethereum mainnet, one of them has 50,082 records, one has 3,215, and one has never been called.
Every discussion of trust for autonomous agents eventually points at ERC-8004. It is the standard that gives an agent a portable on-chain handle, a place to accumulate feedback, and a hook for third parties to attest that the work was done correctly. We covered the proposal when it was new in EIP-8004: trustless agents, and we read the first empirical study of it in Auditing ERC-8004, which measured registration files and reviewer behavior through May 2026.
This post does something different. Instead of reading the paper, we read the contracts, then queried the chains. We cloned erc-8004/erc-8004-contracts on August 17, 2026 (HEAD b9e466c, committed August 15; repo created October 8, 2025; 231 stars, 107 forks, 54 open issues) and read every line of Solidity in it. Then we asked Ethereum and Base what those contracts actually contain.
The gap between the two answers is the story.
What is actually deployed
The canonical proposal at eips.ethereum.org/EIPS/eip-8004 is still Draft, created August 13, 2025, authored by Marco De Rossi, Davide Crapis, Jordan Ellis and Erik Reppel, and requiring EIP-155, EIP-712, EIP-721 and ERC-1271. Draft status has not slowed deployment. The repo's README documents 25 mainnet sections and 25 testnet sections, from Ethereum and Base to Injective, 0G, Robinhood Chain and SKALE.
All three registries are UUPS proxies at vanity addresses mined with CREATE2 through the Safe singleton factory, so the same address appears on every chain. On mainnets:
// mainnet proxies, identical on 25 chains
IdentityRegistry 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
ReputationRegistry 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63
ValidationRegistry 0x8004Cc8439f36fd5F9F049D9fF86523Df6dAAB58
The first observation is documentary. The README publishes the Identity and Reputation addresses for all 50 networks and never publishes the Validation address for any of them. The Validation Registry appears in the README only as prose, under a warning that the section of the spec is "still under active update and discussion with the TEE community". Its address lives in scripts/addresses.ts, not in the docs.
But it is deployed. We queried Ethereum mainnet directly: the proxy at 0x8004Cc84… returns code, getVersion() returns 2.0.0, owner() returns the same address as the other two registries, and getIdentityRegistry() resolves correctly to 0x8004A169…. It is wired, initialized, and reachable. Same on Base.
We also confirmed the deployment window by binary-searching for the first block with code at each address. On Ethereum, the Identity Registry proxy appeared at block 24,339,871 and the Validation Registry at 24,339,874 — 36 seconds apart, on January 29, 2026. On Base, blocks 41,663,783 and 41,663,785, on February 3, 2026. All three registries went live together, in one session, on both chains.
What each registry contains
The Identity Registry keeps its counter in ERC-7201 namespaced storage, so the number of registrations can be read directly from the slot without trusting an indexer. Reading slot 0xa040f782…4e00 on August 17, 2026:
// Identity Registry _lastId — total registrations
Ethereum mainnet 0xc3a2 = 50,082 agents
Base mainnet 0xf94f = 63,823 agents
For reputation and validation we counted events from the deployment block to the head of the chain, using two independent query shapes — one full-range request and one chunked scan with recursive splitting — and took only the numbers where both agreed. On Ethereum mainnet, from block 24,339,871 through 25,773,811:
// ReputationRegistry 0x8004BAa1… on Ethereum
NewFeedback 3,215
ResponseAppended 37
FeedbackRevoked 0
Upgraded 2
// ValidationRegistry 0x8004Cc84… on Ethereum
ValidationRequest 0
ValidationResponse 0
Zero. Not a low number — the literal absence of a single validation request in the six and a half months since the registry went live on Ethereum, on the chain where 50,082 agents registered. Base is where the only activity exists, and it is small: 13 ValidationRequest events and 8 ValidationResponse events since February 3.
The reputation numbers deserve a second look too. Decoding the indexed topics of those 3,215 NewFeedback events on Ethereum gives 1,668 distinct agentId values and 653 distinct client addresses. So 3.3% of registered Ethereum agents have ever received a single piece of on-chain feedback, and the entire reputation graph of the flagship deployment is built by fewer than seven hundred addresses. Nobody has ever revoked feedback on Ethereum.
This is a sharper version of the finding in the empirical audit we covered in July. That study found most registration files were placeholders. The contract-level view adds that two of the three trust primitives are, as deployed, statistically unused: the identity layer has volume, the reputation layer has a trickle, and the validation layer has nothing at all.
Who can rewrite the trust layer
All three registries are upgradeable, and the upgrade gate is one line in each implementation:
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
So the question is who the owner is. We called owner() on all three proxies on Ethereum and on Base. Every one of them returns 0x547289319C3e6aedB179C0b8e8aF0B5ACd062603. That address has no code on Ethereum mainnet, which makes it a plain EOA — not a multisig, not a timelock, not a governance contract.
The address is not incidental. It is hardcoded in the placeholder implementation used for the vanity deployment:
function initialize(address identityRegistry_) public initializer {
__Ownable_init(address(0x547289319C3e6aedB179C0b8e8aF0B5ACd062603));
__UUPSUpgradeable_init();
_identityRegistry = identityRegistry_;
}
The deployment flow in the repo expects OWNER_PRIVATE_KEY in a .env file, generates pre-signed upgrade transactions for the three proxies, and broadcasts them. The repo's own operator guidance says to "use multi-sig or timelock for production" and to "consider transferring ownership to governance". On the two chains we checked, that has not happened.
This is not a hypothetical capability. The Reputation Registry on Ethereum has emitted two Upgraded events, which is exactly what the two-phase vanity strategy predicts: the proxy first points at the minimal placeholder, then gets upgraded to the real implementation. The upgrade key has already been exercised in production. The ERC-1967 implementation slot of the Identity Registry on mainnet currently holds 0x7274e874…, the same implementation address that appears in the repo's pre-signed upgrade artifact, which is a useful confirmation that mainnet runs the code we read.
Upgraded, not just on the proxy.
What the Solidity actually enforces
Read as code rather than as a standard, the registries enforce less than the vocabulary suggests — with one genuinely careful exception.
That exception is the agentWallet key, and it matters most for payments. It is a reserved metadata key: setMetadata() and the metadata overload of register() both revert with "reserved key" if you try to write it. It is initialized to the registrant's address at mint. Changing it requires the new wallet to prove control, via an EIP-712 typed signature or an ERC-1271 contract signature over a struct that binds agentId, newWallet, owner and deadline, where the deadline must be within five minutes:
bytes32 private constant AGENT_WALLET_SET_TYPEHASH = keccak256(
"AgentWalletSet(uint256 agentId,address newWallet,address owner,uint256 deadline)");
uint256 private constant MAX_DEADLINE_DELAY = 5 minutes;
And it is cleared on transfer — the _update override wipes agentWallet whenever the NFT changes hands, so a new owner must re-prove the payout address. For a payment gateway this is the single most useful field in the standard: the address where an agent gets paid cannot be set by a third party and does not survive a change of ownership.
The reputation side is thinner. giveFeedback() blocks only self-dealing, by asking the Identity Registry whether the caller is the owner or an approved operator of the agent:
require(!IIdentityRegistry(_identityRegistry).isAuthorizedOrOwner(msg.sender, agentId),
"Self-feedback not allowed");
One fresh address per review defeats that, which is why the read path, not the write path, carries the anti-Sybil design: getSummary() on the Reputation Registry reverts with "clientAddresses required" if you pass an empty list. You cannot ask the chain "what is this agent's score" — only "what is this agent's score according to these specific clients". That is the right call, and it is the standard's most honest line of code.
The same discipline is missing next door. The Validation Registry's getSummary() accepts an empty validatorAddresses array and treats it as "no filter", iterating every validation ever recorded for that agent and returning an unweighted average of uint8 responses. A single validator can move an agent's global average. Meanwhile appendResponse() on the Reputation Registry has no authorization check at all: any address can attach a response URI to anyone's feedback, and each new responder is pushed into an unbounded array. Both getSummary() and readAllFeedback() loop over nested unbounded structures, so on-chain aggregation degrades toward the call gas ceiling as an agent accumulates history.
One more detail with semantic consequences: feedback is stored as int128 value plus uint8 valueDecimals, and getSummary() normalizes every entry to 18 decimals, averages, then rescales the result to the most frequent valueDecimals in the set. The meaning of the number is carried only by two free-text tags. Filter loosely and the contract will happily average a latency measurement with a dollar amount and hand you a clean-looking score.
The judged picks the judge
The deepest structural point is not a bug, it is the direction of the call. In the Validation Registry, validationRequest() must be called by the owner or operator of the agent being validated. The agent chooses its validator, initiates the request, and points at the off-chain payload the validator will examine. Validators then answer with a uint8 between 0 and 100, and the spec explicitly allows validationResponse() to be called repeatedly for the same requestHash to model progressive finality.
That is the issuer-pays rating agency model, on-chain. Incentives and slashing are, by the spec's own words, "managed by the specific validation protocol and are outside the scope of this registry". The registry records claims; it does not make them expensive to fake. The project's open issues say the same thing in plainer language: issue #28, "Rogue validators can manipulate validation response values" (January 27, 2026), issue #16, "[Proposal] Support Refreshing/Expiring/Revoking a Validation" (January 3, 2026), and issue #12, "Inconsistency between Validation and Registration implementations" (November 20, 2025). A validation, once recorded, never expires.
Given that, the zero on Ethereum reads less like neglect and more like accurate market pricing of an unfinished primitive.
The payment seam
ERC-8004 is deliberately not a payments standard. The spec says payments "are orthogonal to this protocol and not covered here", and the README repeats it. What is interesting is where payments leak in anyway, and how thin those hooks are.
The agent registration file — the JSON that agentURI resolves to — carries a single boolean:
{
"services": [ { "name": "A2A", ... }, { "name": "MCP", ... } ],
"x402Support": false,
"supportedTrust": ["reputation", "crypto-economic", "tee-attestation"]
}
A boolean is not a payment requirement. Compare it with what an x402 server actually returns in its accepts array — scheme, network, asset, maxAmountRequired, payTo, expiry — which we walked through in the x402 protocol post. x402Support: true tells a discovering agent that a paywall probably exists somewhere behind the endpoint. It does not tell it which chain, which stablecoin, which scheme, or how much. Discovery and pricing remain separate lookups.
The other hook is on the feedback side. The optional off-chain feedback file includes a proofOfPayment object with fromAddress, toAddress, chainId and txHash, annotated in the spec as "this can be used for x402 proof of payment". That is the interesting primitive: reputation entries that are attached to a settled transaction, which is much harder to manufacture at scale than a fresh address leaving a five-star review. Note that chainId here is a bare string, not a CAIP-2 identifier, and the object has no reference to the payment scheme.
Both hooks sit under an unresolved editorial dispute. The spec source in the repo still carries the EIP editor's inline comment on the x402 sentence: "This is a coinbase thing, right? If it isn't necessary to your standard, can you omit it?" The trust layer and the payment layer have not agreed on how tightly to couple.
What it means for LLM4Agents
LLM4Agents is a gateway: agents authenticate, call models, and pay per use in stablecoins over x402 and EIP-3009. ERC-8004 touches that in three places, and the audit changes the priority order of all three.
First, getAgentWallet() is usable today, and it is the part of the standard with real cryptographic content. An agent identity whose payout address was proven by EIP-712 or ERC-1271 and is automatically invalidated on transfer is a better payTo source than a self-asserted address in a config file. It is a small, verifiable primitive we can read from any of 25 mainnets at the same address.
Second, reputation is not yet an input we can price risk on. With 653 distinct clients producing all Ethereum feedback and no way to ask for a global score, any use of the Reputation Registry has to be explicitly allowlist-shaped: we choose whose feedback counts, pass those addresses to getSummary(), and treat the result as one signal among several. That is the design the contract pushes you toward, and it is the correct one.
Third, validation is a roadmap item, not a dependency. A registry with zero Ethereum usage, no expiry semantics, an unfiltered average, and an open issue about validator manipulation cannot gate access to a paid endpoint. The honest version of "we support ERC-8004 validation" today would be an integration nobody exercises.
The threat side is worth stating plainly. If a gateway treats an ERC-8004 agentId as an authorization primitive, it inherits the upgrade key. Identity is cheap — 50,082 registrations on Ethereum, most of them, per the earlier audit, without a live endpoint — so an agentId proves that someone paid gas, nothing more. Identity is for resolution and attribution; authorization stays with the bearer token or the signed payment, as we argued in Bearer vs x402.
Staying on the frontier
Concrete steps, in the order we would take them.
1. Resolve, don't trust. Add an optional agentId field to agent registration on the gateway, and resolve it against the Identity Registry: read ownerOf, tokenURI and getAgentWallet, fetch the registration file, and verify that its registrations array points back at the same agentRegistry and agentId. Store the result as metadata attached to the account, never as a permission.
2. Pin the implementation. Record the ERC-1967 implementation address behind each registry proxy we read, per chain, and alert when it changes. An Upgraded event on a registry we depend on is an operational incident, not a changelog entry. This is cheap to build and it is the specific mitigation for a single-EOA upgrade key.
3. Publish payment-anchored feedback. When an agent settles an x402 invoice on the gateway, we hold exactly the fields the spec's proofOfPayment object wants. Emitting feedback whose off-chain file carries the settlement hash — and whose value encodes something objective, like successful completion of paid calls — is a way to seed the one kind of reputation entry that costs money to fake. Keep the tags stable so the on-chain average stays semantically coherent.
4. Prefer payTo resolution over trust scores. Wire getAgentWallet() into refund and revenue-share paths before wiring any score into access control. The wallet field is verifiable now; the score is not.
5. Watch the validation revision, don't integrate ahead of it. The registry's own README says the TEE-facing part of the spec will be revised. The signals to watch are expiry semantics for validations, any weighting or staking requirement for validators, and whether requests can be initiated by the client rather than by the agent being judged. If that last one changes, validation becomes usable as an admission gate. Until then, the observability approach we described in agent evaluation and observability produces better trust signals than the chain does, because we control the measurement.
ERC-8004 is doing the useful half of its job. Identity resolution across 25 mainnets at one address, with a cryptographically proven payout field, is real infrastructure. The trust half is still a schema waiting for an economy — and the numbers say the economy has not shown up yet.
Agent identity is resolution, not authorization
Register an agent, top up in USDC, and pay per call over an OpenAI-compatible gateway.
Register agent