ERC-8001 Agent coordination framework

Final · Other · created 2025-08-02

A framework in which multiple automated programs (agents) agree on a single task without a trusted intermediary. A proposer posts an intent, and it can be executed only when all participants accept it with signatures.

Why it is needed

In decentralized finance (DeFi), blockchain games, and automated commerce, situations often arise in which multiple agents must act together without a trusted coordinator. However, the existing intent standards ERC-7521 and ERC-7683 define only flows initiated by a single party and do not specify how to verify that multiple parties have actually agreed. As a result, projects building multi-party tasks had to design their own agreement verification methods, and each also had to guard against signatures being reused elsewhere (replay) and participant lists being manipulated. This standard fills that gap with the smallest possible onchain mechanism. It gathers the proposer's EIP-712 signed intent and each participant's acceptance signature, and unifies the rules so that the intent becomes executable only when all required acceptances have been collected and are valid.

What to implement

In depth

Three typed data structures and the domain

The standard defines three structures: AgentIntent, CoordinationPayload, and AcceptanceAttestation. AgentIntent holds payloadHash, expiry, nonce, agentId, coordinationType, coordinationValue, and participants, and participants MUST include agentId itself. CoordinationPayload holds version, coordinationType, coordinationData, conditionsHash, timestamp, and metadata, where coordinationData is opaque bytes from the core's point of view. AcceptanceAttestation holds intentHash, participant, nonce, expiry, conditionsHash, and signature. The EIP-712 domain is fixed as {name: "ERC-8001", version: "1", chainId, verifyingContract}, and exposing the domain through ERC-5267 is recommended.

Hash computation rules and getIntentHash

The participants array MUST be in strictly ascending order by uint160(address) with no duplicates, and participantsHash is computed as keccak256(abi.encodePacked(participants)). getIntentHash(intent) MUST return the struct hash (intentStructHash), not the full signing digest, and AcceptanceAttestation.intentHash MUST also be that struct hash. Each acceptance signs its own EIP-712 digest that includes this intentHash field. The field names of ACCEPTANCE_TYPEHASH must exactly match the Solidity struct.

Six status codes

The implementation must use enum Status { None, Proposed, Ready, Executed, Cancelled, Expired } as is. None is the default value when no intent exists, Proposed means the intent has been proposed but not all acceptances have been collected, Ready means all participants have accepted and it can be executed, Executed means execution is complete, Cancelled means explicit cancellation, and Expired means it expired without being executed or cancelled. getCoordinationStatus must return exactly this value in each situation.

proposeCoordination validation rules

It must revert if the signature does not verify the intent under the ERC-8001 domain, if intent.expiry is less than or equal to block.timestamp, if intent.nonce is not greater than getAgentNonce(intent.agentId), if participants is not a strictly ascending list without duplicates, or if agentId is not in participants. On success it emits a CoordinationProposed event, the status becomes Proposed, the stored nonce equals the submitted nonce, and getRequiredAcceptances must equal the number of participants.

Conditions for acceptance and execution

acceptCoordination reverts when the intent does not exist or has expired, when the caller is not a participant, when the caller has already accepted, when the signature is invalid, or when attestation.expiry is less than or equal to the current time. executeCoordination reverts when the status is not Ready, when the intent has expired, when any one of the acceptances has expired, or when the hash of the submitted payload differs from payloadHash. If the execution is valid, it attempts the action described by executionData, returns (success, result), and the status becomes Executed. The validity period of an acceptance is checked both at acceptance time and at execution time.

Cancellation authority and nonce rules

Before expiry only the proposer can cancel, and after expiry anyone can cancel. When cancelled, a CoordinationCancelled event is emitted and the status becomes Cancelled. The nonce must increase with each valid new intent, and a nonce that is not greater than the stored value must be rejected. The nonce on the acceptance side is optional, but if implemented it must be strictly monotonically increasing per participant. It is recommended to signal errors with descriptive custom errors such as ERC8001_ExpiredIntent, ERC8001_BadSignature, ERC8001_NotParticipant, ERC8001_DuplicateAcceptance, and ERC8001_PayloadHashMismatch.

Intentionally omitted

This standard does not cover privacy, reputation, threshold policies, bonding, or cross-chain semantics. These features are left to be built as optional modules that reference this specification. The scope is narrowed to a single chain to avoid coupling with bridge semantics and keep the base primitive easy to audit. Sorting the participant list removes hash malleability and enables off-chain deduplication, and separating the intent from the acceptance lets signatures be collected off-chain so that the on-chain check is reduced to a single pass.

Things to watch out for

Original ERC · ← ERCs