EIP.tools

EIP.tools

⚠️ DraftStandards Track: ERC

ERC-8165: Agentic Onchain Operations

End-to-end workflow for agent-issued intents, permissionless fulfillment, atomic settlement, and verifiable receipts

Authors
Created2026-02-18
Discussion Linkhttps://ethereum-magicians.org/t/erc-8165-agentic-on-chain-operation-interface/27773
Requires

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/re...
Pull Request#1549PR open

EIP-GPT summary

Contents
AbstractMotivationNon-goalsSpecificationDefinitionsAgentic Workflow ModelWorkflow ActorsWorkflow StatesCanonical Execution LoopApplicabilityIntent StructureField SemanticsFee AccountingRequirementsProfilesProfile A β€” Registered Intent (On-chain)Profile B β€” Unregistered Intent (Off-chain)Intent ID ComputationDomain BindingIntentHub InterfaceRequired: IIntentHubOptional: IIntentHubOffchain (Profile B)Optional: IIntentHubReceiptsSettlement Receipt StructureERC-165 Interface DetectionSettlement RulesExecution SemanticsOptional ModulesRationaleInteroperability & AdoptionWorkflow ExamplesBackwards CompatibilitySecurity ConsiderationsAuthoring and SigningDistributionSolvingExecutionVerificationCopyright

Abstract

This ERC standardizes the canonical workflow interface for agentic on-chain operations. It defines a signed intent envelope expressing core safety bounds (maximum input, minimum output, validity windows, and replay protection), a permissionless settlement surface enabling competitive solver fulfillment, and structured settlement receipts providing verifiable workflow closure.

The standard separates intent authorship from solving and execution, enabling autonomous agents, solvers, and users to coordinate around outcome-based objectives. Core safety bounds are enforceable on-chain by every compliant hub. Additional policies MAY be enforceable via optional constraint modules. Every outcome is recorded via machine-readable receipts suitable for post-execution verification and structured record-keeping.

This ERC provides a common vocabulary and interface for agentic on-chain operations: a standardized lifecycle and receipts that make agents interoperable across runtimes and ecosystems.

Motivation

Ethereum transactions encode execution instructions rather than desired outcomes. Emerging agent systems require a mechanism to express goals without prescribing execution paths.

Many systems define "orders" or "intents," but these systems vary in lifecycle semantics, signature domains, and receipt formats. The ecosystem lacks a standard lifecycle and uniform settlement receipts that make agents interoperable across runtimes. Without a shared workflow interface, each agent-solver pair must negotiate bespoke formats, verification procedures, and completion signals β€” fragmenting the ecosystem and limiting composability.

While ERC-8004 standardizes trustless agent identities and reputation, it does not define how agents express actionable objectives or how such objectives are executed and verified on-chain.

This proposal introduces:

  • A canonical intent envelope with core safety bounds enforceable on-chain by every compliant hub
  • Optional constraint modules for additional policies, with a standard enforcement hook
  • A permissionless fulfillment interface supporting on-chain and off-chain intent distribution
  • Atomic settlement guarantees with structured receipt events
  • A standardized workflow lifecycle from authorship through verification

The goal is to enable autonomous agents, solvers, and builders to coordinate around outcome-based execution while preserving user safety, composability, and auditability. This ERC defines the minimal workflow closure primitive β€” core safety bounds enforceable on-chain, structured receipts, and optional constraint modules β€” needed for agents to treat on-chain actions as composable, verifiable skills.

Non-goals

This ERC does not standardize:

  • Execution routing: solver strategies, DEX selection, bridging logic, or multi-call sequencing remain implementation-specific.
  • Agent cognition or learning: while receipts are designed to be suitable for agent memory and skill systems, this ERC does not prescribe how agents process or store outcomes.
  • Cross-chain messaging: settlement occurs on a single chain; cross-chain coordination is out of scope.
  • Token economics: fee structures beyond the declared feeBps parameter are not standardized.
  • Delegation and permissioning: authorization between a principal and an authoring agent is a wallet-policy concern and is out of scope for this ERC.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Definitions

  • Maker: Entity issuing an intent (the Principal).
  • Fulfiller: Entity executing an intent (the Executor).
  • Intent: Signed constraint envelope describing acceptable execution outcomes.
  • IntentHub: Contract implementing settlement logic and emitting receipts.
  • Settlement Receipt: Structured event data emitted upon fulfillment, providing verifiable workflow closure.
  • Registered Constraint Module: A constraint module is considered registered iff IConstraintRegistry.resolve(constraintsHash) returns module != address(0) for a given constraintsHash. If constraintsHash == bytes32(0), no module is registered and the hub MUST skip module validation.

Agentic Workflow Model

This section defines the canonical workflow that this ERC standardizes: the actors, lifecycle states, and execution loop that together form an interoperable agent execution loop.

Workflow Actors

RoleDescription
Principal (Maker)The accountable owner of funds and constraints. Signs the intent envelope.
Authoring AgentConstructs intents on behalf of the Principal. May be the Principal themselves or a delegated agent. Identified by agentIdentity in the intent.
SolverSearches for an execution plan that satisfies the intent's constraints. Computes executionData.
Executor (Fulfiller)Submits the on-chain transaction that performs settlement. May be the same entity as the Solver.
IntentHubThe settlement contract that enforces constraints, executes atomic settlement, and emits receipt events.

Workflow States

Intents progress through the following lifecycle states. These are normative semantics; implementations MAY represent them differently internally but MUST exhibit equivalent behavior.

Draft ──► Signed ──► Published ──► Executable ──► Fulfilled
                                       β”‚
                                       β”œβ”€β”€β–Ί Cancelled
                                       β”‚
                                       └──► Expired
StateDescription
DraftIntent constructed off-chain; not yet signed.
SignedPrincipal has produced a valid EIP-712 signature over the intent.
PublishedIntent is distributed β€” either submitted on-chain (Profile A) or relayed off-chain (Profile B).
ExecutableWithin the validity window (validAfter ≀ now ≀ validUntil) and nonce not consumed.
FulfilledAtomic settlement has been executed; receipt emitted. Terminal state.
CancelledPrincipal has explicitly invalidated the intent. Terminal state.
ExpiredvalidUntil has passed without fulfillment. Terminal state.

Canonical Execution Loop

The system defined by this ERC supports the following six-step workflow. The intent envelope enables steps 1–4 (off-chain); on-chain components MUST enable steps 5–6.

  1. Author: An agent or user constructs an Intent envelope specifying outcome constraints and safety bounds.
  2. Sign: The Principal signs the intent using EIP-712 structured data. Signature verification MUST support EIP-1271 where the maker is a contract wallet, in addition to EOA (ECDSA) signatures.
  3. Distribute: The signed intent is published β€” either submitted on-chain via submitIntent (Profile A) or relayed off-chain to solver networks (Profile B).
  4. Solve: One or more solvers compute an execution plan (executionData) that satisfies the intent's constraints.
  5. Execute: A fulfiller calls the IntentHub's fulfill function, triggering atomic settlement.
  6. Verify & Record: The IntentHub emits structured receipt events. Agents and monitoring systems can verify completion and store structured results for post-execution analysis, attribution, and record-keeping.

Applicability

This ERC standardizes a minimal safety envelope covering the common asset-moving core: maximum input, minimum output, validity windows, and replay protection. The core envelope standardizes bounded asset transfer outcomes; any multi-step objective is expressed as a bounded envelope plus constraint modules and executionData. This core applies to swaps, rebalancing, lending operations, bridge-and-execute sequences, and any operation expressible as bounded asset transfers. Native asset transfers (e.g., ETH) are out of scope; MAY be supported via wrapped tokens or hub-specific extensions.

Arbitrary non-universal objectives β€” such as governance voting, NFT acquisition criteria, or custom DeFi strategies β€” MUST be expressed via discoverable constraint modules referenced by constraintsHash. The core envelope remains intentionally minimal to maximize interoperability across agent runtimes and solver implementations.

Intent Structure

Intents MUST be signed using EIP-712 structured data. Implementations MUST include chainId and verifyingContract in the EIP-712 domain separator.

Intent {
    address maker;
    address inputToken;
    uint256 inputAmountMax;
    address outputToken;
    uint256 outputAmountMin;
    address receiver;
    uint48  validAfter;
    uint48  validUntil;
    uint256 nonce;
    bytes32 constraintsHash;
    uint256 feeBps;
    bytes32 salt;
    address agentIdentity;
}

Field Semantics

  • maker: The Principal's address. MUST match the signer (or be authorized via EIP-1271).
  • inputToken / outputToken: ERC-20 token addresses for the input spent and output received.
  • inputAmountMax: Maximum input the maker is willing to spend (gross, before fees).
  • outputAmountMin: Minimum output the receiver must obtain (net, after fee deduction). MUST be enforced during settlement. See Fee Accounting below.
  • receiver: Address that receives the output tokens.
  • validAfter / validUntil: Unix timestamps defining the validity window. validUntil MUST be greater than validAfter.
  • nonce: Replay protection. MUST prevent replay per maker. nonce MAY be sequential or arbitrary; hubs MUST treat it as an opaque value and enforce uniqueness only.
  • constraintsHash: The keccak256 hash of the canonical encoding of additional constraint rules. RECOMMENDED encoding is a v1 canonical encoding defined as abi.encode(bytes4 constraintsType, bytes constraintsData), where constraintsType is a 4-byte identifier that references a published constraint spec. constraintsType identifiers SHOULD be derived from a namespaced hash β€” e.g., bytes4(keccak256("com.example.ConstraintName:v1")) β€” to minimize collision risk. Collision resistance is best-effort due to 4-byte truncation; registries SHOULD reject registrations where a constraintsType value is already in use for a different spec. Implementations MAY alternatively store a registry-resolvable pointer. See Constraint Discoverability in Optional Modules. Opaque, undiscoverable hashes reduce interoperability.
  • feeBps: Fee in basis points relative to the gross output. MUST NOT exceed 10,000. Declared as uint256 for ABI slot uniformity; values above 10,000 MUST be rejected. See Fee Accounting below.
  • salt: Additional entropy for intent uniqueness.
  • agentIdentity: The identity of the authoring agent that constructed the intent. This is distinct from the fulfiller/executor, which is recorded in the settlement receipt.

Fee Accounting

To avoid ambiguity between gross and net amounts, the following definitions apply:

  • outputAmountGross: The total output produced by the execution, before fee deduction.
  • feeAmount: Computed as floor(outputAmountGross * feeBps / 10_000). Integer floor division MUST be used.
  • outputAmountNet: The amount delivered to the receiver, equal to outputAmountGross - feeAmount. This MUST be β‰₯ outputAmountMin.

feeBps MUST NOT exceed 10,000. A value of 10,000 is technically valid but results in outputAmountNet = 0; such an intent MUST fail unless outputAmountMin == 0. Makers SHOULD set outputAmountMin > 0 to guard against this.

The following invariants MUST hold for every settled intent:

feeAmount     = floor(outputAmountGross * feeBps / 10_000)
outputAmountNet = outputAmountGross - feeAmount
outputAmountNet β‰₯ outputAmountMin

All receipt fields (outputAmountGross, outputAmountNet, feeAmount) and the IntentFulfilled event MUST use these definitions consistently. Amounts MUST be derived from observed balance deltas rather than trusting token return values, to correctly handle fee-on-transfer and rebasing tokens. Concretely: inputAmountUsed = makerInputBalanceBefore βˆ’ makerInputBalanceAfter; outputAmountGross = receiverOutputBalanceAfter βˆ’ receiverOutputBalanceBefore. If the hub acts as an intermediary (e.g., via transferFrom, permit, or a pull-based pattern), hub balance deltas SHOULD be used when the hub is the accounting boundary. Input transfer MAY use any approved pull mechanism; this ERC does not mandate transferFrom exclusively.

outputAmountGross is derivable as outputAmountNet + feeAmount and is therefore not explicitly included in the IntentFulfilled event to save gas.

A nonce MAY be reused on a different hub, since replay protection is scoped to (hub.domainSeparator, maker, nonce). Cross-hub replay of a signed intent is not possible unless the maker signs an intent for each hub independently.

Requirements

  • Expired or fulfilled intents MUST be rejected.
  • Signature verification MUST support EIP-1271 where the maker is a contract, in addition to standard EOA (ECDSA) verification.

Profiles

This ERC defines two submission profiles to accommodate different distribution models. Implementations MUST support at least one profile.

Profile A β€” Registered Intent (On-chain)

In Profile A, the intent and signature are submitted on-chain before fulfillment.

  • submitIntent(intent, signature) stores the intent and signature, returning an intentId.
  • fulfill(intentId, executionData) references the stored intent.

Profile A is RECOMMENDED because it enables deterministic signature verification without requiring the fulfiller to carry the full intent calldata in every fulfill transaction. This reduces gas costs for fulfillers and simplifies verification logic.

Profile B β€” Unregistered Intent (Off-chain)

In Profile B, the intent is relayed off-chain (e.g., via solver networks or intent pools).

  • fulfill(intent, signature, executionData) receives the full intent and signature inline.
  • The IntentHub computes intentId deterministically from the intent.

Profile B is common in competitive solver markets where intents are distributed off-chain to maximize solver participation. Implementations MAY support Profile B.

Cancellation: Cancellation via cancelIntent is defined only for intents submitted on-chain (Profile A). For Profile B, intents have no on-chain registration to cancel. Off-chain cancellation is accomplished by the maker consuming the (maker, nonce) pair β€” either by fulfilling a different intent or by submitting and cancelling a Profile A intent with the same nonce. A hub MAY offer a cancelBySig(Intent, signature) extension for off-chain-originated cancellations, but this is NON-STANDARD and not required for compliance.

Profile B-only hubs: Implementations supporting only Profile B MUST still emit IntentFulfilled receipts and MUST still enforce (maker, nonce) uniqueness. They MAY be otherwise stateless (no on-chain intent storage required), apart from nonce tracking.

Intent ID Computation

This ERC uses two distinct hash values that align with EIP-712 terminology:

  • intentStructHash: The EIP-712 struct hash of the Intent, independent of the domain:
intentStructHash = keccak256(abi.encode(
    INTENT_TYPEHASH,
    intent.maker, intent.inputToken, intent.inputAmountMax,
    intent.outputToken, intent.outputAmountMin, intent.receiver,
    intent.validAfter, intent.validUntil, intent.nonce,
    intent.constraintsHash, intent.feeBps, intent.salt, intent.agentIdentity
))

The canonical EIP-712 type string is:

INTENT_TYPEHASH = keccak256(
    "Intent(address maker,address inputToken,uint256 inputAmountMax,"
    "address outputToken,uint256 outputAmountMin,address receiver,"
    "uint48 validAfter,uint48 validUntil,uint256 nonce,"
    "bytes32 constraintsHash,uint256 feeBps,bytes32 salt,address agentIdentity)"
)

The field order in the type string MUST match the abi.encode encoding order above.

  • intentDigest: The EIP-712 typed-data digest, which binds the struct to a specific domain (chain + hub):
intentDigest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, intentStructHash))

intentId MUST equal intentStructHash. Using the struct hash makes intentId portable across domains (useful for Profile B off-chain relay), while replay protection is enforced separately by domain-bound signature verification on intentDigest. intentId is an indexing and correlation primitive β€” authorization is enforced by verifying intentDigest, not intentId.

Domain Binding

The EIP-712 domain separator MUST include verifyingContract. It is RECOMMENDED that verifyingContract be set to the target IntentHub address. This prevents cross-hub replay attacks at the cost of making intents non-portable across hub deployments.

Rationale: Binding intents to a specific hub via intentDigest prioritizes safety over portability. An intent signed for Hub A cannot be replayed on Hub B even if intentId (the struct hash) is the same. If portability across hubs is required, makers MUST sign separate intents per hub OR employ an adapter that introduces a unique domain separator to prevent replay. Implementations targeting multi-hub ecosystems MAY define adapter mechanisms, but cross-hub portability introduces replay risks that MUST be explicitly mitigated.

IntentHub Interface

Contracts compliant with this ERC MUST implement IIntentHub. Implementations MAY additionally implement IIntentHubOffchain (Profile B) and/or IIntentHubReceipts.

Required: IIntentHub

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

interface IIntentHub is IERC165 {

    /// @notice Emitted when an intent is submitted on-chain (Profile A).
    event IntentSubmitted(bytes32 indexed intentId, address indexed maker);

    /// @notice Emitted when a maker cancels an intent.
    event IntentCancelled(bytes32 indexed intentId);

    /// @notice Emitted upon successful fulfillment with structured receipt data.
    /// @dev maker is the accountable principal (signer of the intent); receiver is the payout address. They MAY differ.
    /// @dev fulfiller is indexed for workflow attribution. receiver is not indexed because it can
    ///      be filtered off-chain from non-indexed fields; prioritising maker and fulfiller
    ///      maximises ergonomics for wallet and solver analytics.
    /// @dev feeRecipient defaults to msg.sender if not specified via constraint module semantics.
    /// @dev executorAgent MAY be address(0) if the executor is unknown or undeclared.
    event IntentFulfilled(
        bytes32 indexed intentId,
        address indexed maker,
        address indexed fulfiller,
        address receiver,
        address inputToken,
        uint256 inputAmountUsed,
        address outputToken,
        uint256 outputAmountNet,
        uint256 feeAmount,
        address feeRecipient,
        address executorAgent
    );

    /// @notice Submit an intent and signature on-chain.
    function submitIntent(
        Intent calldata intent,
        bytes calldata signature
    ) external returns (bytes32 intentId);

    /// @notice Cancel a previously submitted intent. Only callable by the maker.
    /// @dev MUST mark (maker, nonce) as used, preventing any future fulfillment
    ///      of any intent sharing that (maker, nonce) pair, regardless of other fields.
    function cancelIntent(bytes32 intentId) external;

    /// @notice Fulfill a registered intent by intentId.
    function fulfill(
        bytes32 intentId,
        bytes calldata executionData
    ) external returns (uint256 outputAmountNet);

    /// @notice Returns the EIP-712 domain separator currently used for intentDigest verification.
    /// @dev MUST reflect the domain separator in active use. If the hub's chainId or domain
    ///      parameters change (e.g., after an upgrade), this MUST return the updated value.
    ///      Hubs that cannot guarantee domain stability MUST NOT allow domain changes after
    ///      deployment without invalidating all outstanding intents.
    function domainSeparator() external view returns (bytes32);
}

Optional: IIntentHubOffchain (Profile B)

Implementations supporting Profile B MUST implement this interface.

interface IIntentHubOffchain is IERC165 {

    /// @notice Fulfill an unregistered intent by providing intent + signature inline.
    function fulfill(
        Intent calldata intent,
        bytes calldata signature,
        bytes calldata executionData
    ) external returns (uint256 outputAmountNet);
}

Optional: IIntentHubReceipts

Implementations supporting on-chain receipt queries MUST implement this interface.

interface IIntentHubReceipts is IERC165 {

    /// @notice Query the settlement receipt for a fulfilled intent.
    function getReceipt(
        bytes32 intentId
    ) external view returns (SettlementReceipt memory);
}

Settlement Receipt Structure

struct SettlementReceipt {
    address fulfiller;
    address receiver;
    address inputToken;
    uint256 inputAmountUsed;
    address outputToken;
    uint256 outputAmountGross;  // total output before fees
    uint256 outputAmountNet;    // delivered to receiver = outputAmountGross - feeAmount
    uint256 feeAmount;          // floor(outputAmountGross * feeBps / 10_000)
    address feeRecipient;
    address executorAgent;
    uint256 settledAt;          // block.timestamp of settlement
    bytes32 executionHash;      // OPTIONAL: keccak256(executionData), for correlation only
}

executionHash is OPTIONAL. When provided, it MUST be computed as keccak256(executionData). It is intended solely for traceability and correlation β€” it does NOT provide privacy guarantees, as executionData is typically visible in calldata.

executorAgent is an OPTIONAL attribution field. It is self-declared by the fulfiller and carries no on-chain authentication guarantee unless validated by an external registry (e.g., ERC-8004). executorAgent MAY be address(0) if the executor is unknown or undeclared; implementations MAY default it to agentIdentity from the intent when no override is provided. Consumers SHOULD NOT rely on executorAgent for access control or trust decisions without independent verification.

feeRecipient: A constraint module MAY specify feeRecipient via its constraint semantics. If not overridden, feeRecipient MUST default to msg.sender (the fulfiller). There is no feeRecipient field in the core intent envelope.

ERC-165 Interface Detection

Compliant implementations MUST implement ERC-165 interface detection.

  • supportsInterface(bytes4 interfaceId) MUST return true for 0x01ffc9a7 (ERC-165).
  • supportsInterface(bytes4 interfaceId) MUST return true for the interface id of IIntentHub.
  • Implementations supporting Profile B MUST return true for the interface id of IIntentHubOffchain; claiming Profile B support without this signal is non-compliant.
  • Implementations supporting receipt queries MUST return true for the interface id of IIntentHubReceipts.
  • Implementations SHOULD compute interface ids using type(IIntentHub).interfaceId, type(IIntentHubOffchain).interfaceId, and type(IIntentHubReceipts).interfaceId respectively.
  • Interface ids MUST remain stable across upgrades; introducing breaking changes to these interfaces requires a new ERC.

Settlement Rules

During fulfill execution, implementations MUST:

  1. Verify signature correctness by validating the signer over intentDigest (computed using this IntentHub's EIP-712 domainSeparator), supporting both ECDSA and EIP-1271. For both profiles, this verification MUST use the hub's domainSeparator even though intentId is intentStructHash. If isValidSignature reverts, the hub MUST treat the signature as invalid and revert.
  2. Verify time window validity (validAfter ≀ block.timestamp ≀ validUntil).
  3. Ensure nonce has not been used. Implementations MUST enforce uniqueness per (maker, nonce) globally within the hub, regardless of which profile is used. Tracking fulfilled[intentId] is OPTIONAL (useful for quick receipt lookups) but MUST NOT substitute for (maker, nonce) uniqueness enforcement β€” two intents sharing the same (maker, nonce) but differing only in salt or constraintsHash would each have distinct intentIds, so fulfilled[intentId] alone is insufficient.
  4. Ensure intent is neither cancelled nor already fulfilled. If constraintsHash == bytes32(0), constraint module validation MUST be skipped (see Constraint Discoverability in Optional Modules).
  5. Ensure the total input transferred from the maker does not exceed inputAmountMax.
  6. Ensure receiver obtains at least outputAmountMin as outputAmountNet (see Fee Accounting).
  7. Execute settlement atomically (all-or-nothing within a single transaction).
  8. Transfer feeAmount to the fee recipient. If not specified by a constraint module, feeRecipient MUST default to msg.sender (the fulfiller).
  9. Emit the IntentFulfilled event with all receipt fields.

If any condition fails, the transaction MUST revert.

Execution Semantics

Execution paths are intentionally NOT standardized.

executionData MAY encode arbitrary routing logic including:

  • DEX aggregation
  • Bridging
  • Lending operations
  • Multi-call execution

Additional operations MAY be executed atomically within settlement, but implementations MUST preserve settlement safety guarantees.

Optional Modules

Signature-Based Authorization

Implementations MAY support signature-based token authorization mechanisms (e.g., permit-style approvals) to reduce interaction overhead prior to fulfillment.

Commit–Reveal Mode

Implementations MAY support a commit–reveal mechanism:

commitIntent(bytes32 commitHash)
revealIntent(Intent intent, bytes signature, bytes32 salt)

This mode MAY mitigate information leakage and front-running risks in competitive solver environments.

Bond Requirement

Implementations MAY require fulfillers to stake collateral or provide bonded guarantees to reduce spam, malicious execution, or settlement griefing.

Incremental Fulfillment

Implementations MAY allow incremental (partial) fulfillment across multiple transactions. If supported, implementations MUST define:

  • Whether nonce is consumed at the first partial fill or upon full completion.
  • Whether outputAmountMin is enforced per partial fill or cumulatively across all fills.
  • How receipt events represent partial vs. complete settlement.

Incremental fulfillment adds significant complexity and is NOT part of the core specification. Implementations supporting it SHOULD document their partial-fill semantics explicitly.

Constraint Discoverability and Enforcement

Core compliance enforces the core settlement properties declared in Settlement Rules (signature, time, nonce, cancellation/fulfillment status, input max, output min, fee). constraintsHash is NOT enforced by the hub unless the hub supports a constraint module mechanism.

Implementations SHOULD support a discoverable mechanism for solvers to resolve constraintsHash to interpretable constraint rules. The RECOMMENDED encoding is abi.encode(bytes4 constraintsType, bytes constraintsData) where constraintsType identifies a published spec.

Implementations MAY support on-chain enforcement via an optional constraint module interface. If supported, the hub MUST follow this order for every fulfill with a registered constraint module:

  1. Verify signature, time, and nonce status (steps 1–3 of Settlement Rules).
  2. Resolve the module via IConstraintRegistry.resolve(constraintsHash).
  3. Call module.validate(intent, executionData) β€” MUST occur before any transferFrom(maker, …) or external call that could move maker funds.
  4. Mark (maker, nonce) as used (e.g., nonceUsed[maker][nonce] = true). Implementations MAY additionally record fulfilled[intentId] = true for receipt lookup convenience. Both MUST be set before any external calls in step 5.
  5. Execute transfers and external calls.

The hub MUST revert if validate reverts. The hub MUST obtain constraintsData from the registry; the intent does not carry constraintsData inline. If constraintsHash == bytes32(0), the hub MUST skip steps 2–3. Equivalently, if resolve(constraintsHash) returns module == address(0), the hub MUST treat this as "no constraint module" and skip validation.

The hub SHOULD be aware that validate() MAY make external calls and could be re-entrant. Implementations SHOULD either restrict accepted modules to a trusted allowlist (e.g., governance-controlled registry, immutable allowlist, or deploy-time configuration), or apply standard reentrancy protections (e.g., checks-effects-interactions pattern) around the validate call. Hubs SHOULD also guard against gas-grief attacks from unbounded validate() execution β€” e.g., by calling the module via staticcall with an explicit gas limit, or by requiring modules to declare a bounded gas usage.

interface IConstraintModule {
    /// @notice Validate that executionData satisfies the intent's additional constraints.
    /// @dev MUST revert with a descriptive reason if constraints are not satisfied.
    /// @dev MUST be a view function β€” MUST NOT mutate state.
    /// @dev Modules SHOULD avoid relying on secrets embedded in executionData;
    ///      commit–reveal is recommended when secrecy matters.
    function validate(
        Intent calldata intent,
        bytes calldata executionData
    ) external view;
}

interface IConstraintRegistry {
    /// @notice Publish a constraints preimage for discoverability.
    /// @dev Anyone MAY call this; the registry stores (constraintsType, constraintsData,
    ///      module) keyed by keccak256(abi.encode(constraintsType, constraintsData)).
    /// @dev Registry entries SHOULD be immutable once published for a given constraintsHash.
    ///      Mutable registries MUST clearly document the upgrade/swap policy and associated
    ///      replay/DoS implications; makers MUST be aware that a module swap after signing
    ///      could alter constraint semantics without a new signature. Registries SHOULD reject
    ///      registrations where `module == address(0)`.
    function publishConstraints(
        bytes4 constraintsType,
        bytes calldata constraintsData,
        address module
    ) external returns (bytes32 constraintsHash);

    /// @notice Resolve a constraintsHash to its module, raw data, and type identifier.
    function resolve(bytes32 constraintsHash)
        external view
        returns (address module, bytes memory data, bytes4 typeId);
}

Constraint modules and registries are OPTIONAL and not required for base compliance. Implementations providing a registry SHOULD advertise support via ERC-165 interface detection or an initialization event.

ERC-8004 Compatibility

If agentIdentity is provided, implementations MAY query ERC-8004 registries for reputation or validation status. This ERC does not require ERC-8004 but is designed to interoperate with it.

Rationale

  • Separating intent definition from execution enables competitive fulfillment markets while maintaining safety guarantees.

  • The six-step workflow (Author β†’ Sign β†’ Distribute β†’ Solve β†’ Execute β†’ Verify & Record) provides a complete lifecycle that agents can implement uniformly, regardless of the solver infrastructure or execution environment.

  • Structured settlement receipts close the workflow loop: agents can verify outcomes, attribute execution to specific fulfillers, and store structured results without parsing transaction traces.

  • Two submission profiles (A and B) accommodate both on-chain-first architectures and off-chain solver markets without mandating a single distribution model.

  • This ERC complements EIP-7521 by standardizing on-chain intent settlement semantics and atomic execution guarantees, while EIP-7521 focuses on generalized intent expression formats.

  • The design avoids introducing new transaction types, allowing deployment without protocol upgrades.

  • ERC-165 is used for capability discovery (Profile B, receipt queries) rather than static assumptions about function existence, enabling safe and composable hub detection across heterogeneous deployments and avoids brittle selector probing patterns.

  • Execution routing remains intentionally unspecified to preserve composability, extensibility, and innovation across different solver and agent implementations.

Interoperability & Adoption

This ERC is designed as a shared interface layer between agent runtimes, solver networks, and settlement infrastructure.

Wallets and agents need only know how to construct and sign the intent envelope (EIP-712) and how to read structured receipt events to verify completion.

Solvers compete permissionlessly. They need only produce valid executionData that satisfies an intent's constraints. No integration with other solvers is required.

IntentHub provides a uniform settlement surface. By implementing this interface, any hub becomes accessible to any compliant agent or solver.

Workflow Examples

Example 1: Agent rebalances portfolio across DEXs
  1. Author: An agent detects portfolio drift and constructs an intent to swap 1,000 USDC for at least 0.5 ETH.
  2. Sign: The user's smart contract wallet signs via EIP-1271.
  3. Distribute: Intent is submitted on-chain (Profile A).
  4. Solve: Multiple solvers compute routes across Uniswap, Curve, and Balancer.
  5. Execute: The winning solver calls fulfill with optimal routing in executionData.
  6. Verify & Record: The agent reads the IntentFulfilled event, confirms 0.52 ETH received, and records the outcome.
Example 2: Agent executes bridge + swap + repay atomically
  1. Author: An agent constructs an intent to bridge USDC from L2 to mainnet, swap to DAI, and repay an Aave loan β€” expressed as a single intent with constraints.
  2. Sign: EOA signature via EIP-712.
  3. Distribute: Intent relayed off-chain to specialized cross-protocol solvers (Profile B).
  4. Solve: A solver constructs a multi-call execution plan encoding bridge, swap, and repay steps.
  5. Execute: The solver calls fulfill(intent, signature, executionData) on the IntentHub.
  6. Verify & Record: Receipt confirms input spent and loan repayment, closing the workflow.

Backwards Compatibility

This ERC introduces no consensus changes and remains fully compatible with existing Ethereum transactions and smart contracts.

This ERC defines a new interface. Existing intent hub implementations are not expected to be compatible without modification. Implementations targeting backwards compatibility with pre-existing systems MAY implement adapter contracts that translate between legacy interfaces and this standard.

Implementations MAY support legacy event formats for transitional purposes but MUST emit the IntentFulfilled event with all receipt fields specified in this standard when claiming compliance.

Security Considerations

Security analysis is organized by workflow phase to map threats to their point of origin and corresponding mitigations.

Authoring and Signing

  • Delegation abuse: A malicious authoring agent may construct intents that do not reflect the Principal's goals. The agentIdentity field provides attribution, enabling post-hoc audit and accountability. Implementations MAY integrate with ERC-8004 reputation systems for pre-execution agent validation.
  • Signature safety: EIP-712 structured data signing ensures the maker can inspect intent parameters before signing. Domain binding (chainId + verifyingContract) prevents cross-chain and cross-hub replay. EIP-1271 support enables contract wallets to enforce additional authorization policies.

Distribution

  • Front-running: Publicly distributed intents may be observed and exploited by MEV searchers. Implementations MAY support commit–reveal mechanisms to mitigate information leakage.
  • Time bounds: validAfter and validUntil limit the exposure window for distributed intents.

Solving

  • Misleading execution plans: A solver may construct executionData that technically satisfies constraints but extracts value (e.g., via sandwich attacks within the execution). The outputAmountMin enforcement provides a hard floor, and the inputAmountMax provides a hard ceiling, but solvers may still extract surplus between these bounds.
  • Constraint enforcement: constraintsHash enables additional policy checks beyond the core bounds. Implementations SHOULD make constraint semantics discoverable to solvers.

Execution

  • Malicious fulfiller: A fulfiller may attempt griefing (reverting after partial execution) or fund extraction. Atomic settlement ensures all-or-nothing execution. Bond requirements (optional) MAY further disincentivize malicious behavior.
  • Nonce tracking: MUST be enforced per maker to prevent replay attacks. Implementations MUST ensure that a nonce cannot be reused even across Profiles A and B.
  • Fee extraction: feeBps MUST be enforced to not exceed the declared value. Implementations SHOULD ensure that fee logic cannot be manipulated to drain maker funds beyond declared parameters.

Verification

  • Receipt integrity: IntentFulfilled events MUST accurately reflect the settlement outcome. Receipt fields (inputAmountUsed, outputAmountNet, feeAmount) MUST correspond to actual token transfers executed during settlement and follow the Fee Accounting definitions.
  • Deterministic Intent ID: The intentId computation MUST be deterministic to enable off-chain verification and prevent ambiguity in receipt correlation.
  • executionHash correlation: When provided, executionHash is for traceability only and does NOT provide privacy guarantees. Agents and monitoring systems SHOULD NOT rely on executionHash for confidentiality.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth