Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-8410: Portable Execution Plan Artifact

A portable JSON format for ordered calls, typed-data signing requests, and integrity-checked references

Authors Moody Salem (@moodysalem)
Created 2026-09-04
Discussion Link https://ethereum-magicians.org/t/erc-8410-portable-execution-plan-artifact/29587
Requires EIP-155, EIP-712

Abstract

This ERC defines a JSON format for an ordered sequence of calls from one account on one chain. An execution plan includes the calls, required execution capabilities, and optional simulation failure advice. A keccak256 plan digest identifies the calls and their step labels.

The standard also defines a typed-data signature request for one EIP-712 message and an artifact reference for retrieving either document type by URL with byte-length and integrity checks. Producers prepare the documents; wallets validate and authorize them independently.

Motivation

Applications commonly prepare calls for a wallet to execute. A shared document format allows routing services, protocol front ends, and automation tools to submit these calls without a separate integration for each wallet.

Related calls, such as approval, swap, and allowance cleanup, need an explicit order and may require atomic execution. A portable plan records these requirements together and provides an identifier for review and audit records. It can be stored, queued, or reviewed on another device without retaining the connection on which it was prepared.

When a document passes through an intermediary, a reference allows the wallet to retrieve the original bytes directly and detect modification relative to the reference. Typed-data signature requests support workflows that require offchain signatures before a transaction is prepared, or that do not require the wallet to broadcast a transaction.

This ERC specifies the documents, digests, and retrieval rules. Producer APIs and wallet authorization policies are outside its scope.

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.

Machine-readable schemas are provided for the execution plan, the typed-data signature request, and the artifact reference.

A producer prepares a document. A consumer is the wallet that validates it and decides whether to sign or execute it. A relay passes a document or reference from the producer to the consumer.

Quantity encoding

A quantity is a JSON string holding a canonical unsigned decimal integer: the single character 0, or an ASCII digit string with no leading zero. A quantity MUST fit in a uint256.

A byte string is a JSON string of the form 0x followed by an even number of hexadecimal digits. An address is a byte string of exactly 20 bytes. Producers MUST emit both in lowercase. Consumers MUST normalize both to lowercase before computing the digest, and MAY additionally reject input that is not already lowercase.

Execution plan

Field Type Required Description
schema_version string yes MUST be "1" for this revision
chain_id quantity yes EIP-155 chain identifier the plan executes on
caip2_chain_id string yes MUST equal eip155: concatenated with chain_id
sender address yes Account expected to send every step
ordered_steps array yes 1 to 4096 steps, in execution order
required_capabilities array of string no Behaviors the consumer must implement
simulation_failure_policy object no What the producer advises on failure
extensions object no Producer-defined data the consumer ignores

A document containing a member not listed here MUST be rejected. Consumers MUST reject unsupported schema_version values and inconsistent chain identifiers.

Steps

Each entry of ordered_steps is an object:

Field Type Required Description
step integer yes 1-indexed position; entry n MUST have step equal to n
kind string yes One of the step kinds below
transaction object yes The call to make
revert_decode object no ABI for rendering a revert from this step

transaction has the following members:

Field Type Required Description
chain_id quantity yes MUST equal the plan’s chain_id
from address yes MUST equal the plan’s sender
to address yes Call destination
data byte string yes Calldata
value quantity yes Native token value, in wei
gas quantity no Suggested gas limit

Unknown step and transaction members MUST be rejected. A transaction without to cannot be represented; the format does not directly support contract creation transactions. Consumers MUST reject a plan containing inconsistent chain or sender values rather than execute it partially.

gas is advisory. A consumer MUST NOT broadcast a producer-supplied gas limit without its own estimation.

kind explains why a step is in the plan, and MUST be one of:

  • execution — a call the user asked for.
  • approval — grants a spending allowance a later step needs.
  • allowance_cleanup — revokes an allowance an earlier step granted.
  • signature_dependent_execution — spends a signature approved earlier.
  • other — none of the above.

kind is a producer-supplied label for display. Consumers MUST NOT derive authority from it or assume that the calldata implements the labeled operation.

revert_decode, when present, is an object with kind equal to error_result, an abi array holding a JSON ABI fragment declaring at least one error, and an OPTIONAL boolean required defaulting to false. required indicates whether the producer considers decoding necessary to explain the failure; consumers MAY ignore it. Consumers MUST treat the decoded result as display text only and MUST bound the fragment they accept. The schema permits at most 128 ABI entries; the reference implementation also limits the fragment to 65536 bytes.

Required capabilities

required_capabilities lists behaviors required to execute the plan. A consumer MUST reject a plan naming any capability it does not implement.

This revision defines one capability:

  • atomic_batch — every step executes in a single transaction that reverts as a whole if any step fails.

Consumers can satisfy atomic_batch through an account-abstraction batch executor or an EIP-7702 delegation to a batching implementation.

A multi-step plan that does not list atomic_batch MAY be executed as separate transactions. A consumer doing so MUST execute steps in order, MUST NOT begin a step until the previous one has been mined successfully, and MUST stop at the first failure. A consumer that can execute atomically MAY do so regardless of whether the plan asks for it.

Capability names MUST contain 1 to 64 ASCII characters in the range 0x21 to 0x7e. A plan MUST NOT list more than 32 capabilities. Additional capabilities may be defined by later proposals.

Simulation failure policy

When present, simulation_failure_policy MUST contain all three of rpc_error, execution_reverted, and simulation_setup_error. Each is an object with an action and a human-readable instruction of 1 to 2000 characters.

action MUST be one of:

  • retry_same_plan — the failure is transient; the identical document may be retried.
  • reprepare_plan — the document is stale; ask the producer for a new one.
  • user_review — do not retry automatically; surface it to a human.

execution_reverted and simulation_setup_error MUST NOT specify retry_same_plan.

The policy is advisory. Consumers MAY ignore it and MUST NOT treat it as authorization to broadcast.

Extensions

extensions is an object reserved for producer-defined data. Consumers MUST ignore its contents and MUST bound its serialized size; 65536 bytes is RECOMMENDED. It is excluded from the digest, so a producer MUST NOT place in it anything that changes what executes or what a reviewer needs to see.

Size limits

A consumer MUST enforce limits on any plan it accepts and MUST reject rather than truncate. Plans MUST contain at most 4096 steps. Additional RECOMMENDED limits are 8 MiB of data summed across steps and 16 MiB of serialized document.

Plan digest

The plan digest is the keccak256 hash of the UTF-8 serialization of a canonical JSON object built from the plan:

{
  "schema_version": "1",
  "chain_id": "1",
  "sender": "0x...",
  "ordered_steps": [
    {
      "step": 1,
      "kind": "approval",
      "transaction": {
        "chain_id": "1",
        "from": "0x...",
        "to": "0x...",
        "data": "0x...",
        "value": "0"
      }
    }
  ]
}

The serialization MUST place members in exactly the order shown, MUST contain no whitespace between tokens, and MUST encode addresses and data as lowercase byte strings. step MUST be serialized as a JSON number and every other scalar as a JSON string. Strings MUST be emitted without optional JSON escapes; step MUST use decimal integer notation without a fractional or exponent part.

This member order is normative and is not lexicographic. A generic canonicalizer such as RFC 8785 sorts members by name and would order the outer object chain_id, ordered_steps, schema_version, sender, producing different bytes and a different digest. Implementations MUST emit the order given here rather than delegating to a general-purpose canonicalization routine.

The digest covers schema_version, chain_id, sender, and each step’s step, kind, and transaction chain_id, from, to, data, and value. It excludes caip2_chain_id (derivable from chain_id), gas, revert_decode, simulation_failure_policy, required_capabilities, and extensions.

The plan digest identifies this projection, not the complete document or a signed transaction. Plans with different gas hints or capability requirements can have the same digest. The artifact reference’s integrity digest, defined below, covers the complete serialized document instead.

Consumers SHOULD display the digest wherever they display a plan for approval, SHOULD record it against the resulting approval, and SHOULD record it against the broadcast transaction hash.

The digest does not authenticate the producer or establish authorization.

Typed-data signature requests

A typed_data_signature_request is a separate document carrying one concrete EIP-712 message and the account expected to sign it. The typed-data signature request specification is normative for this document type. It defines the request and result shapes, the request digest, and optional delivery of the signature to the producer.

Supporting signature requests is OPTIONAL. A consumer that supports execution plans only MUST reject signature requests. A signature request MUST NOT be encoded as an execution-plan step or placed in its ignored extensions field.

Producers MAY return several signature requests, receive their results, and then return another concrete signature request or an execution plan. Each new document requires its own validation and authorization. No execution plan is required when the workflow ends with an offchain signature and producer relay.

Delivery by reference

A plan or typed-data signature request MAY be supplied inline or by an artifact reference. The reference identifies a document for the consumer to retrieve and verify.

Field Type Required Description
kind string yes MUST be "artifact_reference"
artifact_type string yes "execution_plan" or "typed_data_signature_request"
url string yes https URL, data: URI, or file URI locating the bytes
integrity object conditional Digest over the exact stored bytes
bytes integer conditional Nonnegative exact byte length of the stored bytes
instruction string no Human-readable note from the producer

integrity and bytes are REQUIRED when url is an https or file URL, and OPTIONAL when it is a data: URI. When either is supplied for a data: URI it MUST still be checked. Consumers MUST ignore unrecognized top-level members of the envelope.

integrity is an object with algorithm, which MUST be "keccak256" for this revision, and value, 0x followed by 64 hexadecimal digits. A consumer MUST reject an integrity object containing any other member.

artifact_type MUST be exactly execution_plan or typed_data_signature_request. No other artifact types are defined or accepted by this revision. A consumer MUST reject a type it does not implement, and MUST reject a reference whose artifact_type differs from the one expected at the point of use.

In the retrieval rules below, the maximum document size and validation rules are those of the selected type. Fetching a signature request MUST NOT use the larger execution-plan size limit merely because the envelope is shared.

instruction is producer-supplied display text and MUST NOT influence any authorization decision.

Retrieval

Given an envelope, a consumer MUST, in this order:

  1. Reject the envelope if its serialized length exceeds the consumer’s limit, before parsing the URL.
  2. Reject the reference if bytes is present and exceeds the document type’s size limit, before opening any connection or reading any file.
  3. Retrieve the bytes according to the transport rules below. A consumer that does not implement the file transport MUST reject a file envelope.
  4. Reject the result if bytes is present and the retrieved length differs.
  5. Reject the result if integrity is present and the digest of the retrieved bytes differs.
  6. Parse and validate the bytes exactly as it would a document of that type supplied inline.

Where the transport applies a content encoding, length and integrity checks apply to the decoded bytes. Successful verification establishes that the bytes match the reference, not that the document is authorized.

File transport

A file URI identifies a document on the consumer’s local filesystem. Support for this transport is OPTIONAL.

A consumer fetching a file URL MUST enforce all of the following and MUST reject the reference if any condition cannot be met:

  • The URI has an empty host or localhost, and names an absolute path.
  • integrity and bytes are present; a file reference without them is rejected before any read.
  • The bytes are read once, bounded by the document type’s size limit during reading, and the length-then-digest checks above are applied before parsing.
  • Missing, oversized, mismatched, and unreadable files fail indistinguishably, and error messages MUST NOT include any part of the file contents.
  • No network access is performed for the read.

Consumers SHOULD additionally restrict file reads to one or more user-configured directories and treat anything outside them as failure.

HTTPS transport

A consumer fetching an https URL MUST enforce all of the following and MUST reject the reference if any condition cannot be met:

  • The scheme is https on the default port.
  • The URL carries no userinfo component and no fragment.
  • The host resolves, and every address it resolves to is a public unicast address. Loopback, link-local, unique-local, and other private ranges MUST be refused.
  • Redirects are not followed.
  • No credentials, cookies, or ambient authorization are attached.
  • The response body is bounded by the document type’s size limit, enforced during reading, and the bound applies to the decoded stream where a content encoding is in use.
  • Connection and total timeouts are enforced, and the number of concurrent retrievals is bounded.

Error messages MUST NOT include any part of the response body.

Data URI transport

A data: URI MUST have media type application/json, MAY use the ;base64 parameter, and MUST decode to at most the document type’s size limit. Consumers MUST bound the encoded length before decoding and MUST NOT perform network access for a data: reference.

For a decoded limit of N bytes, padded base64 requires at most 4 × ceil(N / 3) characters before percent-encoding. Percent-encoding can use three characters per encoded byte. The encoded-length bound must account for the URI prefix and the encoding used; the decoded-size limit still applies.

Provenance

A consumer reporting provenance MUST distinguish the HTTPS host from which it retrieved a document from a data: URI, which provides no producer provenance. A caller-supplied file path MUST NOT be presented as provenance beyond the local machine. Authorization policies MAY use the observed HTTPS host, but TLS does not establish the trustworthiness of documents hosted there.

Relationship to wallet_sendCalls

A consumer or producer supporting EIP-5792 MAY convert a plan’s calls to wallet_sendCalls parameters:

Plan wallet_sendCalls
chain_id (decimal) chainId (hexadecimal)
sender from
ordered_steps[n].transaction.to / data calls[n].to / data
ordered_steps[n].transaction.value (decimal) calls[n].value (hexadecimal)
atomic_batch in required_capabilities atomicRequired: true
kind, revert_decode, simulation_failure_policy, extensions no equivalent; dropped

When converting to a plan, caip2_chain_id is derived from chainId, the resolved from account becomes sender, steps are numbered consecutively, and every step’s kind is execution. Transaction quantities are converted to decimal strings, omitted data and value become "0x" and "0", and atomicRequired: true becomes atomic_batch. The resulting plan is subject to the same validation as any other plan. Calls without a destination cannot be represented.

This mapping does not preserve all metadata. In particular, changing a step’s kind changes the plan digest. A round trip preserves the digest only if all digest-covered fields are preserved. Capabilities without an equivalent in the destination format cannot be preserved by this mapping.

The mapping alone does not establish execution compatibility. EIP-5792 does not require an atomic batch to use a single transaction, whereas atomic_batch does. Non-atomic execution of a plan also requires waiting for each preceding step to be mined successfully and stopping on failure. Consumers executing a converted plan remain subject to these requirements.

Rationale

Document format

EIP-5792 specifies a wallet interface for submitting calls. This ERC defines a document that can be stored and exchanged independently of that interface. Its digest provides a common identifier for approval and execution records, and its reference form supports retrieval without forwarding the document body.

Restricting each plan to one sender and one chain allows one wallet account to validate and execute the complete sequence. Cross-chain and multi-account workflows can coordinate several plans outside this format.

Quantity encoding

Decimal strings avoid the precision limits of JSON numbers in implementations using IEEE-754 doubles. They also allow quantities to be read without converting from hexadecimal. Addresses and calldata remain hexadecimal byte strings. The redundant caip2_chain_id supports configuration that uses namespaced chain identifiers; requiring agreement with chain_id prevents conflicting values.

Digest scope

Gas is excluded because consumers estimate it against current state. This allows gas estimation to change without changing the identity of the calls. The wallet remains responsible for gas limits and fee policy.

The plan digest and reference integrity digest serve different purposes. The former identifies the ordered calls and labels; the latter detects any change to the serialized document, including fields excluded from the plan digest.

Required capabilities

Ignoring an unsupported capability could change execution semantics. For example, executing an approval, swap, and cleanup as separate transactions can leave an allowance active if a later step fails. Requiring consumers to reject unsupported capabilities prevents this implicit fallback.

Reference envelope

A separate envelope provides a URL, document type, byte length, and integrity digest in a transport-independent format. Keccak256 is used consistently for plan and reference digests. Subresource Integrity alone does not define the document types or retrieval rules needed here.

Unknown envelope members are ignored to allow additional metadata. Unknown integrity members are rejected because they may express verification requirements the consumer does not implement.

Redirects are prohibited to keep retrieval and provenance checks limited to the URL supplied in the reference.

Backwards Compatibility

This proposal introduces a new document format and no changes to the chain, to existing interfaces, or to deployed contracts. Producers and consumers that do not implement it are unaffected.

Consumers may support execution plans without supporting typed-data signature requests. Existing transaction signing permissions MUST NOT implicitly authorize typed-data signatures.

EIP-5792 conversion is described in the Specification. EIP-7702 is one way to provide atomic execution and is not required by this format.

Test Cases

Execution-plan test vectors cover canonical serialization and digest computation. Each case gives a plan, the exact canonical byte string its digest is taken over, and the resulting digest.

Case Digest
A one-step plan with empty calldata 0x93aeec006e55dfe0f54041d53c94387e08c504d4f3b3826cd3426dbc7da38ea5
A two-step plan, whose step 2 carries a gas hint the canonical form omits 0x13c4b058741ee7bdfe5a51825c71bd205859b89436505a15adf60bd3f2281deb
The same two-step plan with different gas, extensions, required_capabilities, and a different failure instruction 0x13c4b058741ee7bdfe5a51825c71bd205859b89436505a15adf60bd3f2281deb
The same two-step plan with the final byte of step 2 calldata changed 0x5bf27f490fa44998b6386dfe1b0fae6df0c1b2a9604b69d83bbbbd7a6d285549

The third case changes only digest-excluded fields. The fourth changes calldata and therefore has a different digest.

Typed-data signature request vectors cover the request digest, EIP-712 domain binding, delivery constraints, and structural validation. The fixture runner checks both document types and compares EIP-712 hashes from ethers and viem.

Reference Implementation

Ekubo Wallet (github.com/EkuboProtocol/wallet) implements plan validation and digest computation in crates/ekubo-wallet-core/src/core/execution_plan.rs and reference retrieval in crates/ekubo-wallet-core/src/plan_fetch.rs. It records the plan digest with approvals and transaction hashes and uses EIP-7702 batches for atomic multi-step execution.

The Ekubo protocol’s producer at mcp.ekubo.org returns execution plans and artifact references for transfers, swaps, liquidity, and yield operations.

Security Considerations

Authorization

Plans and references are untrusted input. Consumers MUST validate the document and evaluate their own authorization rules against its calls. They MUST NOT use kind, instruction, extensions, or revert_decode output as authorization inputs. Producer descriptions can misrepresent calldata, and a relay may modify or replace a request.

Neither digest authenticates the producer or proves approval. Reference verification detects changes relative to the supplied envelope; a relay able to replace both the document and its reference can supply a different valid pair.

The plan digest excludes required_capabilities. Equal digests therefore do not imply equal execution requirements or interchangeable approvals. Consumers must evaluate those requirements independently of the digest. Gas hints are also excluded and MUST be independently estimated before use.

Simulation and execution

State changes between simulation and inclusion may cause a call to revert or execute differently. Consumers SHOULD re-simulate immediately before signing and MUST NOT treat a stored simulation result as authorization to broadcast.

An EIP-7702 delegation persists beyond the transaction that installs it. A consumer using delegation for batching needs to account for the delegated implementation’s continuing authority.

Resource limits

Unbounded documents, calldata, and ABI fragments can exhaust memory or stall parsing. Consumers MUST apply limits before parsing where the transport allows and MUST reject oversized input rather than truncate it.

Retrieval limits apply to the retrieval implementation, including concurrent requests and timeouts. A consumer decoding a content encoding MUST bound the decoded stream as it decodes.

Revert decoding

Both the ABI fragment and the revert data may be attacker-controlled. Consumers MUST bound the fragment, MUST isolate decoder failures, and MUST escape decoded output before displaying it as untrusted text.

Local file access

A file reference causes the consumer to read with its own filesystem privileges. Directory restrictions limit which files a relay can request. Missing, oversized, mismatched, and unparsable input must produce indistinguishable failures to avoid exposing file contents through errors. Even with uniform failures, a guessed path and digest can confirm file contents if the consumer accepts the document.

Special files can block or have side effects when read. Consumers SHOULD apply read timeouts and treat stalled reads as failures. Consumers that do not support local file access MUST reject file references.

Server-side request forgery

Fetching caller-supplied URLs can expose services on the consumer’s network. Consumers MUST check resolved addresses rather than hostnames alone and SHOULD connect to an address they checked. Otherwise, DNS rebinding can change a public address to a private address between validation and connection. The transport rules prohibit redirects, credentials, and non-default ports, and prevent response bodies from being disclosed in errors.

Reference integrity

Consumers MUST reject a digest mismatch and MUST NOT fall back to using the retrieved bytes. Producers SHOULD serve immutable bodies at each URL. Integrity verification and provenance are separate: a data: URI has no producer provenance, and a file URI establishes only a local source.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Moody Salem (@moodysalem), "ERC-8410: Portable Execution Plan Artifact [DRAFT]," Ethereum Improvement Proposals, no. 8410, September 2026. Available: https://eips.ethereum.org/EIPS/eip-8410.