The PreparedTransaction envelope is exactly what §2.4 of the trustScope spec
points toward but deliberately leaves unspecified:
“Implementations that allow agents to call transaction-creating tools SHOULD
gate execution on a separate human approval layer, independent of trust scope.”
We left it open because defining the envelope shape felt out of scope for a
companion to ERC-8004. Sounds like you’ve been drafting that exact shape.
The composition is clean. An agent hardened by inputSources and trustScope
is one that:
-
Only read declared, sanitized on-chain data
-
Was called within its declared delegation bounds
When that agent produces a transaction, it should emit something a human can
actually review — not raw calldata. PreparedTransaction as the handoff format
between the agent and the wallet signing flow is the right boundary.
Our live implementation for comparison
We have this handoff running on Pixel Goblins and Goblinarinos agents
(gateway.ensub.org). When an agent calls send_transaction, the gateway
creates an approval record and opens a wallet-sign gate before execution.
The current envelope shape:
// Created by the gateway when agent calls send_transaction
ApprovalRecord {
id: string // approval gate identifier
job_id: string // async job this belongs to
agent_registry: string // ERC-8004 registry address
agent_id: string // token ID
owner_address: string // wallet that must sign
tx_data: {
tool: string // MCP tool name (e.g. "send_transaction")
input: Record<string, unknown> // decoded tool arguments from agent reasoning
}
risk_summary: string // populated by agent or left empty
status: "pending" | "approved" | "rejected"
note: string | null // tx hash on approval, rejection reason on decline
}
Key design decisions in the current implementation:
Fresh calldata at signing time — we do NOT sign the calldata the agent
computed during reasoning. At approval time, we re-fetch fresh calldata from
the MCP tool with the same arguments. This prevents stale-quote reverts on
swap transactions where prices move between reasoning and signing.
Agent reasoning → tool_call(send_transaction, { from, to, amount, ... })
↓
Approval gate opens (human reviews decoded args)
↓
Human approves via wallet-sign
↓
Gateway re-calls MCP tool with same args → fresh calldata
↓
MetaMask opens with fresh tx params → user signs → tx hash
↓
Gateway resumes tool loop with { status: "submitted", txHash }
Approval as tool result — the agent doesn’t block waiting for the human.
The job runs async; the approval card appears in the chat UI inline. When the
human approves or rejects, the tool loop resumes with the resolution as the
tool result. The agent can then reason about it — including handling rejections
gracefully rather than looping.
Cancel vs. reject — current implementation has a known behaviour: hitting
“cancel” returns a soft rejection that the agent may retry (treating it as a
transient failure). Hitting “other” returns a user-supplied reason that the
agent treats as a definitive stop signal. A formal rejection status in the
envelope would fix this.
What we’re missing compared to your envelope
Based on your description, the gaps in our current implementation:
| Feature | Our approval gate | PreparedTransaction |
|---|---|---|
| Decoded calldata | Tool args (pre-execution) | Post-simulation decoded |
| Simulation results | Not present | Yes |
| Risk assessment | Empty field, not populated | Yes |
| Validity window | No timeout — gate stays open indefinitely | Yes |
| Formal rejection status | Implicit via “other” | Explicit |
The validity window is the piece I’m most curious about — what happens on
expiry? Does the agent re-run the tool call to produce a fresh envelope, or
does the human have to re-initiate the intent? And does the simulation run
at envelope creation time (agent side) or at signing time (wallet side)?
Proposed §2.4 language update
Once PreparedTransaction gets an ERC number, §2.4 of the trustScope spec
should reference it directly:
“Implementations that allow agents to call transaction-creating tools SHOULD
gate execution on a separate human approval layer conforming to
PreparedTransaction (ERC-XXXX), independent of trust scope. Trust scope
controls invocation rights; it does not authorise individual transactions.
A misconfigured trust scope can at most produce a pending PreparedTransaction
— which the owner can review and decline.”
Happy to align wording once your draft settles. If your ERC lands first, we
reference it. If ours does, we leave §2.4 as a SHOULD and point to yours as
the reference implementation.