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.
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.
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:
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:
Reject the envelope if its serialized length exceeds the consumer’s limit,
before parsing the URL.
Reject the reference if bytes is present and exceeds the document type’s
size limit, before opening any connection or reading any file.
Retrieve the bytes according to the transport rules below. A consumer that
does not implement the file transport MUST reject a file envelope.
Reject the result if bytes is present and the retrieved length differs.
Reject the result if integrity is present and the digest of the retrieved
bytes differs.
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:
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.
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.