This ERC defines an onchain registry of value records for agentic resources. A value record binds an ARD entry, as defined by the Agentic Resource Discovery (ARD) specification maintained by the ards-project working group, to an onchain anchor — a token-bound executable skill, a token-bound task tender, an address-anchored agent identity, or an ARD registry endpoint — and, through a kind adapter, to the address that controls that anchor. Every record is a valid ARD entry, and every resolver that serves records is a conformant ARD registry, so agents and agent users outside Web3 discover and consume onchain value through ordinary ARD search. Authority over a record belongs to an address, never to a domain; a domain is an endorsement that an address collects by claiming it onchain and being acknowledged in the domain’s own ARD manifest. Records are identified by their anchor; ARD URNs are aliases.
Motivation
ARD answers what exists and who says so. A publisher lists its MCP servers, A2A agents, skills and APIs in a manifest under its own domain; registries crawl, index and federate those manifests; a client asks in natural language and receives entries together with the publisher’s identity. ARD deliberately defines nothing beyond discovery: no price, no payment, no settlement, no escrow, no credit. It has no demand side — only resources that are offered, never work that is wanted — and it roots trust in domain ownership.
An agent economy needs the complementary half: what a resource is worth, who stands behind it, and how it settles. Those questions already have onchain answers. A token-bound executable skill commits a package hash and sells calls, epochs, licences or copies. A token-bound task tender escrows a bounty inside the token and settles against verifiers, judges or collective decisions. An address-anchored agent identity turns any address into a dormant identity that becomes active when a live agent is bound to it, and credit assertions attach to it. What is missing is the layer that lets an ordinary ARD client see those answers without a wallet, an RPC endpoint or any knowledge of the chain.
This ERC is that layer. It makes three decisions.
Value root = settlement root. In the agent economy, any party that gets paid already holds an address: the payee of an HTTP 402 payment is an address, the owner of a token is an address, the recipient of an escrowed bounty is an address. Rooting value in the address therefore adds nothing a publisher does not already have, and it keeps the authority that moves money and the authority that describes the offer in the same hands. A domain is not a second root. It is an endorsement an address can collect, and a domain without a key can only publish dormant entries.
Anchor is identity, URN is alias. ARD identifies entries by domain-anchored URNs. Value records are identified by their anchor — a CAIP-19 token identifier or a CAIP-10 account identifier — because that is what the money, the escrow and the identity actually attach to. The controller’s URN becomes the record’s canonical name only while the controller holds a verified binding to that URN’s publisher domain; every gateway can additionally serve the record under its own alias. Equality is decided by anchor, so the same record can be reached through many names and never confused with another.
Kind is posture, type is format. ARD’s type says what format a payload has. A value record’s kind says which side of a trade the entry occupies: an offer, a tender, a subject, or an index. The two are orthogonal. The same MCP server can be offered as a skill and sought by a tender; new payload formats never add kinds.
Two consequences are worth naming. Every existing ARD entry is already a dormant value record (level 0); nothing changes for domain-only publishers until an address anchors their entry. And tenders give ARD a second direction of discovery: a task entry is the first ARD entry whose reader is a supplier looking for work rather than a consumer looking for a tool.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
1. Terms
ARD entry: an entry object as defined by the ARD specification, v0.91: identifier (a URN of the form urn:air:<publisher>:<namespace>:<name>, where <publisher> is a fully qualified domain name), displayName, type (a media type), exactly one of url or data, and optional members including description, tags, capabilities, representativeQueries, version, updatedAt, metadata and trustManifest. This ERC does not restate that specification; the entry schema it relies on is vendored as ard-entry.schema.json, together with its JSON-LD context and licence.
Record: an onchain value record: kind, anchor, descriptor hash, descriptor URI, canonical URN and status.
Anchor: the identity of a record, (chainId, target, id). Rendered as a CAIP-19 asset identifier for token anchors (eip155:<chainId>/erc721:<target>/<id>) and as a CAIP-10 account identifier for address anchors (eip155:<chainId>:<target>, with #<id in hex> appended for a registry anchor).
Controller: the address with authority over an anchor, derived by the kind adapter at call time.
Descriptor: the publisher-authored ARD entry carrying the value members of section 4. Its content members are hashed into the record.
Resolver: software that reads records and domain manifests, computes the resolved members of section 4.3, and serves records. A resolver that exposes the ARD registry interface is a gateway.
Binding: the relation between a domain and an address (section 5).
A kind is a value posture. Its identifier is bytes32 kindId = keccak256("ard-onchain.kind.<name>").
kind
posture
anchor
controller
skill
offer (supply side)
token-bound executable skill token (CAIP-19)
the token owner
task
tender (demand side)
token-bound task tender token (CAIP-19)
the token owner
agent
subject
an address (CAIP-10), id = 0
the address itself
registry
index
an operator address (CAIP-10) with a nonzero id discriminator
the address itself
A registry instance MUST support these four kinds. A new kind MUST correspond to a new value posture; a new payload format MUST NOT introduce a kind. The names assertion, policy and market are reserved for future postures and are not defined by this ERC.
3. Records, anchors and identifiers
recordId = keccak256(abi.encode(block.chainid, target, id)). An anchor has at most one record; registering an anchor that already has a record MUST revert, whatever kind is given.
Anchors MUST be on the chain of the registry instance. The same token on another chain is another anchor and another record.
Records are equal if and only if their anchors are equal. URNs never decide equality.
Canonical URN. The controller MAY supply a URN at registration and on every descriptor update. The URN is the record’s canonical identifier only while (a) the binding between the URN’s <publisher> domain and the current controller is verified (section 5) and (b) that domain’s manifest contains an entry whose identifier equals the URN. Otherwise the record has aliases only, and a resolver that previously served the URN as canonical MUST report it as stale.
Gateway alias. A gateway serving the record under its own domain G MUST use the identifier urn:air:G:onchain:<anchor-encoding>, where <anchor-encoding> is the anchor’s CAIP string, lowercased, with every :, / and # replaced by -. Aliases are per gateway; two gateways serve the same record under two aliases, and clients MUST compare records by value:anchor, not by identifier.
A record MAY have an empty URN. Such a record is served under aliases only.
The descriptorURI of a record is a hint for fetching the descriptor. It is not a trust source: a fetched descriptor is accepted only when its content hash equals the record’s descriptorHash.
4. Descriptor
A descriptor is an ARD entry with the additional members below. Its members fall into three classes.
4.1 Member classes and hash
Publication members — @context, @id, identifier, trustManifest. They belong to whoever publishes the entry: the controller’s own manifest or a gateway serving an alias. They are not hashed; identification is committed by the record’s urn and by the controller address.
Resolved members — the value: members listed in section 4.3. They are computed by resolvers and are never hashed.
Content members — every other member, including the ARD base members (displayName, type, url or data, description, tags, capabilities, representativeQueries, version, updatedAt, metadata) and the authored value: members of section 4.2.
descriptorHash MUST equal SHA-256 over the UTF-8 bytes of the JSON Canonicalization Scheme (RFC 8785) serialization of the content members. Because publication and resolved members are excluded, a gateway alias entry and the controller’s own entry hash to the same value, and a resolver can verify any served copy against the chain.
4.2 Authored value members
The prefix value denotes the IRI
https://eips.ethereum.org/assets/eip-8444/ns#
and the context document is value-context.jsonld. All authored members are OPTIONAL unless stated.
member
value
meaning
value:kind
skill, task, agent or registry
REQUIRED. The posture; MUST equal the record’s kind.
value:controller
did:pkh:eip155:<chainId>:<address>
The controller the publisher declares. In a domain’s manifest this is the acknowledgment of section 5.2.
Offer terms. unit is one of call, epoch, license, copy; amount is a decimal string; currency is a display code; asset is a CAIP-19 identifier when the price is denominated in an onchain asset.
value:settlement
array of { rail, payee, asset?, endpoint? }
Settlement rails. rail is one of onchain, x402, declared; payee is a CAIP-10 account identifier. declared carries no guarantee and is meaningful only at level 0.
value:provenance
object { packageDigest, cardDigest? }
Digests of the anchored package and of the published card, as sha256:<hex>. For skill and task records, packageDigest MUST equal the anchor hint (section 8) for the record to reach level 2.
value:credit
array of { scheme, level, registry }
References to credit assertions about the subject. Referenced, never copied.
value:dispute
object { policyId, registry }
The collective decision policy that governs disputes about the record. Referenced, never copied.
agent only: the ERC-8004 registration file of the bound agent.
value:indexes
array of CAIP-10 identifiers
registry only: the registry instances the endpoint indexes.
The payload of a task descriptor MUST have typeapplication/ai-task+json and MUST carry the tender description in data (or at url) as defined by ai-task.schema.json: wants (payload media types accepted as fulfilment), bounty (amount, currency, optional CAIP-19 asset), and optional specDigest, specURI, cadence, cardinality, copies, acceptance (mode one of verifier, judge, collective, with ref and policyId), deadlines and eligibility. The payload MUST be valid without any onchain member, so that a tender published by a domain without a key is a legal ARD entry.
4.3 Resolved members
Resolvers add the following members to served entries and MUST NOT include them when computing descriptorHash: value:anchor (the anchor’s CAIP string), value:binding (section 5.3), value:level and value:status (section 6), value:aliases (the gateway aliases the resolver serves), value:canonical (the canonical URN, when valid), value:stale (URNs the record carried that are no longer canonical), value:claimedUrn (the record’s URN when it is not canonical), value:registry (the CAIP-10 identifier of the registry instance) and value:descriptorHash (sha256:<hex> of the content members).
5. Domain claims and binding
5.1 Claims (onchain)
An address claims a domain by calling claimDomain, or by having anyone submit claimDomainBySig with an EIP-712 signature of the claim; contract accounts are verified through ERC-1271. The typed data is
EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)
name = "ARD Onchain Registry", version = "1"
DomainClaim(string domain,address controller,uint256 nonce,uint256 deadline)
with nonce equal to nonces(controller) at submission; a successful signed claim increments the nonce. The registry records claims and never adjudicates them: several addresses MAY claim one domain. A domain string MUST be in normalized form — lowercase ASCII letters, digits, - and ., 1 to 253 bytes, no leading or trailing ., no empty label — and domainHash = keccak256(bytes(domain)). Internationalized names MUST be given in their IDNA ASCII (punycode) form.
5.2 Acknowledgment (off-chain)
A domain acknowledges an address in its ARD manifest at /.well-known/ard.json: either a top-level member value:controllers (an array of did:pkh identifiers) containing the address, or an entry whose value:controller is the address. ARD registries ignore both members; resolvers conforming to this ERC read them.
5.3 Binding states
Resolvers compute the binding of a (domain, address) pair as:
state
condition
unbound
the address has no claim on the domain
claimed
the address has a claim and the domain does not acknowledge it; no other address has a claim
verified
the address has a claim and the domain acknowledges it
contested
several addresses have claims; an acknowledged one is verified, every other one is contested
A record’s value:binding is the state of (publisher domain of the record’s URN, current controller), except that unbound is reported as third-party, and a record without a URN reports none. Loss of acknowledgment demotes verified to claimed or contested; the canonical URN then becomes stale. A binding that returns does not retroactively validate anything served while it was absent.
The registry does not verify manifests, and the chain cannot. Where an onchain consumer needs a verified binding — for example a tender whose value:eligibility requires one — the verified state is mirrored onchain as an assertion issued by a party that consumer trusts; this ERC defines no such assertion registry.
6. Levels and status
Record status is one of Active, Suspended, Retired. The controller moves a record between Active and Suspended and from either to Retired; Retired is terminal and binds every later holder of the anchor.
level
condition
L0 dormant
no record exists; value members, if present, are declared and unverifiable
L1 anchored
a record exists with status Active
L2 backed
L1, the kind adapter reports the anchor as backed, and for kinds with an anchor hint the descriptor’s value:provenance.packageDigest equals the hint
Levels and binding states are orthogonal. A client sees a record as the triple (level, binding, credit).
register MUST revert unless kind has an adapter, descriptorHash is nonzero, adapter.exists(target, id) is true, msg.sender == adapter.controllerOf(target, id), and no record exists for the anchor. On success the record is Active, registrant is msg.sender, and Registered is emitted.
updateDescriptor and setStatus MUST revert unless the record exists, is not Retired, and msg.sender equals the controller the adapter reports at that moment. The registry MUST NOT store or cache controllers.
setStatus MUST accept only Active → Suspended, Suspended → Active, and either → Retired.
claimDomain and claimDomainBySig MUST validate the domain as in section 5.1, MUST revert on a duplicate claim by the same address, and MAY bound the number of claimants per domain. claimDomainBySig MUST revert when deadline has passed, when nonce is not the controller’s current nonce, or when the signature does not verify for controller.
registerKind MUST be restricted to the instance owner, MUST revert for a kind that already has an adapter, and MUST revert unless adapter.kind() equals kind. The kind table is therefore write-once; transferring ownership to the zero address makes it final.
controllerOf, backed and anchorHintOf MUST be forwarded to the kind adapter and MUST revert for an unknown record.
The registry MUST implement ERC-165 and return true for the interface above (id 0x881908a5).
Adapters MUST NOT revert from these views; a missing or destroyed anchor is reported as exists == false, controllerOf == address(0), backed == false, anchorHint == 0. The four kinds behave as follows.
kind
exists
controllerOf
backed
anchorHint
skill
target declares the skill kernel interface (id 0x734553a6) through ERC-165 and ownerOf(id) succeeds
ownerOf(id)
the skill binding’s package hash is nonzero
the package hash
task
target declares the tender kernel interface (id 0xc319d532) through ERC-165 and ownerOf(id) succeeds
ownerOf(id)
the tender is not cancelled, its escrow balance is nonzero, and settleBy is zero or in the future
the task hash
agent
target != 0 and id == 0
target
the configured agent identity registry reports the address as active
the digest of the identity’s self-declared document, if any
registry
target != 0 and id != 0
target
never
0
For registry records the RECOMMENDED discriminator is uint256(keccak256(bytes(endpointURL))); it keeps an operator’s registry records distinct from its own agent record. The skill owner, not the skill’s update authority, is the controller: a value record is an offer, and offers belong to holders. The tender owner, not its acceptance authority, is the controller for the same reason.
9. Resolvers and gateways
A resolver builds the served view of a record as follows: it reads the record and the adapter views; it fetches the descriptor; it rejects the descriptor unless the content-member hash equals descriptorHash; it derives the anchor string, the gateway alias, the binding state, the canonical URN, the level and the status; and it emits the content members verbatim with the publication members it owns and the resolved members of section 4.3. A resolver MUST NOT serve a record whose descriptor it could not fetch or whose hash does not match as if it were consistent, and MUST NOT serve Retired records in search results.
A gateway MUST be a conformant ARD registry: it MUST implement the search endpoint with the federation modes auto, referrals and none, SHOULD implement the explore endpoint, MAY implement the listing endpoint, and MUST publish /.well-known/ard.json containing at least one entry of type application/ai-registry+json that describes itself. Every served record MUST carry value:anchor and value:descriptorHash, so that any client can verify it against the chain or against a second gateway. A gateway SHOULD list other gateways of the same instance, gateways of other instances, and ordinary ARD registries as referrals, and MAY register itself as a registry record so that chain-native agents find it.
Rationale
One root. Every earlier design that gave domains and addresses equal standing produced a split authority: a domain could publish a price its key holder had not signed, and a key holder could not prove it owned what a domain said. Making the address the only root, and the domain an endorsement the address collects, removes the split without excluding anyone — a domain that acknowledges an address in its manifest costs the publisher one JSON member, and a publisher with no key stays discoverable at level 0.
Claims onchain, acknowledgment off-chain. The chain cannot read a manifest over HTTPS, so a binding cannot be verified by the registry. Recording claims only, and letting resolvers compute the state from claims plus the manifest, keeps the kernel honest about what it knows; the same split is used for the agent identity’s liveness states, where the chain stores facts and resolvers derive states.
Anchor as identity. ARD’s URN grammar requires a domain, and a record rooted in an address has none until a binding is verified. Treating the URN as an alias instead of fighting the grammar lets every gateway serve every record under a grammar-conformant name, lets a controller’s canonical name appear and disappear with its binding, and makes transfers harmless: a token changes hands, the controller changes, the canonical URN goes stale, the anchor does not move.
Content hash without the envelope. Hashing the identifier would make the commitment depend on the publishing domain, which is exactly what the alias mechanism must be free of. Hashing the content members only means the controller commits to what is offered or wanted, the record commits to the name, and any copy anywhere can be checked.
Controllers derived, never stored. A stored controller is a stale controller after the first transfer. Asking the adapter at every call costs one external view and removes an entire class of bugs. The same reasoning puts the owner, not the update authority or the acceptance authority, in control: the party who can sell or fund the anchor is the party whose offer or tender it is.
A thin kernel. Prices, escrow balances, credit levels and identity states already live in the anchored contracts; copying them into the registry would create a second source of truth that drifts. The registry references them, and adapters read them live. The kernel is not upgradeable and the kind table is write-once, so the rule that was registered is the rule that runs.
Same-chain anchors. A registry can verify an anchor on its own chain and nothing else. Cross-chain duplicates are separate records; linking them is left to a future profile.
Kinds as postures. Tying kinds to payload formats would have doubled the kind table every time a new card format appeared. Four postures cover the trade: what is offered, what is wanted, who trades, and where to look. The reserved names leave room for credit schemes, decision policies and venues to become discoverable in their own right.
The ARD side. The profile depends on ARD’s open entry schema (additionalProperties: true), its JSON-LD extension mechanism and its registry interface, and on nothing else; field names of the upstream specification are vendored and pinned, so that upstream drift is absorbed in the profile rather than in the kernel. The application/ai-task+json payload is designed to be adoptable upstream unchanged.
Contributions to specific parts of this proposal will be credited here by name.
Backwards Compatibility
Every record is a valid ARD entry: an ARD registry that knows nothing of the value namespace indexes it as an ordinary entry with ordinary members. Existing ARD manifests are dormant records; nothing changes for them until an address anchors an entry. No change is required to skill, tender or identity contracts: adapters read their existing views, and the registry writes nothing to them. A registry instance on a chain without an agent identity registry runs the agent kind with an adapter whose backed is always false.
Test Cases
All values below are regenerated by tools/vectors.js in the reference repository and re-derived in Solidity by test/ARDVectors.t.sol; they are reproduced here so that an implementation can be checked without either.
Descriptor hash. For the registry example descriptor the content members canonicalize to
{"description":"ARD registry endpoint indexing the ARD Onchain registry instance on Base. Results carry onchain anchors and descriptor hashes for independent verification.","displayName":"ARD Onchain gateway for Base","representativeQueries":["onchain skills with escrowed bounties","agent tasks paying in USDC on Base"],"type":"application/ai-registry+json","updatedAt":"2026-10-12T00:00:00Z","url":"https://registry.finchip.ai/api/v1/","value:controller":"did:pkh:eip155:8453:0x6666666666666666666666666666666666666666","value:indexes":["eip155:8453:0x7777777777777777777777777777777777777777"],"value:kind":"registry"}
whose SHA-256 is 0xb5a387663102892a0d2bc1679191d4dd35ff4b5e21179fb61a73150b432445b6. The skill example descriptor hashes to 0x8df640a84dbff351a1d67490b42a8d696f5d1232210863e2b469137fe105a6ac, and the gateway alias entry that mirrors it in the example manifest hashes to the same value although its identifier and trustManifest differ.
Gateway alias. Anchor eip155:8453/erc721:0x1111111111111111111111111111111111111111/42 served by registry.finchip.ai has the alias urn:air:registry.finchip.ai:onchain:eip155-8453-erc721-0x1111111111111111111111111111111111111111-42; address anchor eip155:8453:0x2222222222222222222222222222222222222222 has the alias urn:air:registry.finchip.ai:onchain:eip155-8453-0x2222222222222222222222222222222222222222.
Behaviour. The reference test suite covers, among others: registration of each kind; rejection of an unknown kind, an empty descriptor hash, a missing anchor, a non-controller and a second record for an anchor; the agent and registry anchors of one address not colliding; a controller that follows a token transfer while the registrant stays; a destroyed anchor reporting a zero controller and blocking mutation; the status transitions and the terminality of Retired; write-once kind registration; signed claims by an externally owned account and by an ERC-1271 account, with expiry, nonce and replay checks; domain validation; a funded, cancelled and expired tender; an identity moving through active, stale and retired; and the vectors above.
Canonical URN squatting. A canonical URN is valid only under a verified binding, so an address cannot take a name under a domain that does not acknowledge it. Gateway aliases are scoped to the gateway’s own domain and cannot collide with anyone’s canonical name.
Domain hijack and expiry. When a domain changes hands or its manifest changes, acknowledgment disappears and the binding drops to claimed or contested; the canonical URN turns stale and resolvers stop serving it as canonical. Nothing served during a gap is retroactively validated when the binding returns.
Descriptor substitution. The descriptor URI is a convenience. A resolver accepts a descriptor only when its content hash matches the record, so neither a hostile host nor a compromised gateway can change what a controller committed to without the mismatch being visible.
Dishonest resolvers. Every served record carries its anchor and descriptor hash, so a client can reproduce the resolver’s work against the chain or cross-check a second resolver. Score values are relevance, never trust.
Display-name phishing. Names, descriptions and even trust manifests are publisher-authored. Clients should present the anchor, the binding state and the level, and treat a verified binding as the only domain-level trust signal.
Foreign-chain anchors. The registry cannot verify an anchor on another chain, so it refuses them. A record that claims to describe a foreign asset is simply a record about a local one.
Signature replay. Signed claims are bound to the registry’s chain and address through the EIP-712 domain, to the signer through the nonce, and to a time window through the deadline. A claim transaction front-run by a stranger changes nothing: claims are per address and carry no meaning without acknowledgment.
Spam and squatting of anchors. Registration costs gas and requires control of the anchor; only the owner of a token, the address itself or an operator with a chosen discriminator can register, so nobody can register a record about someone else’s anchor.
Stale trust after transfer. A transferred skill keeps its record but changes controller; its canonical URN goes stale, and credit facets that referred to the former controller no longer describe the current one. Resolvers re-derive binding and level on every sync, and clients should read the controller rather than remember it.
Terminal retirement. Retiring a record is irreversible and binds every later holder of the anchor. A controller that wants to pause an offer should suspend it; a buyer should read the record’s status before acquiring an anchor.
Adapter trust. Adapters decide existence, control and backing for a kind, and they are registered write-once by the instance owner. A deployment should publish its adapter addresses with the instance, and an owner that has finished registering kinds should renounce ownership so that the kind table cannot change.