Update ERC-7730: added intent mutability specification#1738
Update ERC-7730: added intent mutability specification#1738PatrickAlphaC wants to merge 11 commits into
Conversation
File
|
kuzdogan
left a comment
There was a problem hiding this comment.
This is very much needed and a very good catch, thank you. Just not approving yet to get some more eyes on and avoid auto-merge.
llbartekll
left a comment
There was a problem hiding this comment.
Thank you for flagging that Patrick. One comment:
StateRef is a full 32-byte slot comparison, but contracts pack multiple vars into one slot, no?
what about optional mask on StateRef? wallet checks (slot_value & mask) == (expectedValue & mask).
{
"slot": "0x0",
"mask": "0x0000000000000000000000ff0000000000000000000000000000000000000000",
"expectedValue": "0x0",
"description": "varX must be false (byte 20 of slot 0)"
}
|
@llbartekll oo. This is a great call!! Yes, I'll add this! Please keep feedback coming. |
|
Ok... I spoke with Laurent from Ledger, and he brought up some good points. He liked the idea of allowing 7730 files to be attached to proxy addresses (not just immutable implementations), with wallets checking proxy slots for changes, and note this would also cleanly support diamond proxies.
I think I like some of these comments... Going to update accordingly. I think we still need a generic
So there is a lot of emphasis on the auditor looking for ways intent can be changed. |
…ty to a metadata object, and setup intent tracking in the contract.context area
|
Ok, my most important question (I think?) for this group now.
Should a wallet:
I think we should have the Then, all "clear signing" should come with a warning? But maybe this should be in the |
|
The commit 4ac1d2b (as a parent of 76cc3fe) contains errors. |
@PatrickAlphaC In your design we technically require protocol developer to self-audit which is not bad too. so maybe descriptors declares the fact of mutability and attestation adds interpretation/correctness, what do you think? |
…ing intent mutability
|
Ok, based on our conversations, we are now going with a more strict implementation for V2, and I've created a ticket in the registry to track any potential V3 changes (specifically for intent mutability tracking): ethereum/clear-signing-erc7730-registry#2558 To respond to @llbartekll, yes, the author would have to get a new attestation. So we've removed that "here are some notes" from the spec as well. And yes, the descriptors must include proxy/stateRef intent mutability. If a function includes another way to have their intent mutate, then it should be omitted from the spec (as of V2 of the schema). |
|
This PR is very verbose, happy to trim it down where needed. |
Add intent-tracking preconditions for upgrade and state-mutability detection
Summary
Adds two optional precondition blocks under
context.contract—proxyandstateRefs— that bind an ERC-7730 descriptor to the on-chain state it was authored against. Wallets verify each declared precondition against live state before applying the descriptor's formatting; on mismatch they downgrade to opaque signing or warn the user. Functions whose displayed intent depends on factors that cannot be expressed via these mechanisms MUST be omitted fromdisplay.formats; wallets fall back to opaque signing for omitted selectors.Discussion thread: https://ethereum-magicians.org/t/eip-7730-proposal-for-a-clear-signing-standard-format-for-wallets/20403
Motivation
A descriptor's
intentandfieldsdescribe a function as it exists at authoring time. The executed behavior can diverge from the displayed intent in ways the descriptor's formatting alone cannot detect:None of these is detectable from the descriptor today. Wallets that clear-sign against a stale descriptor display an intent that the contract no longer honors. The intent-tracking preconditions make the on-chain vectors explicit and verifiable.
Design summary
Two OPTIONAL, additive precondition blocks live under
context.contract:context.contract.proxy— typed block for standardised upgradeable proxies:type— one ofeip1967,eip1822,eip2535. Wallet dispatches on this to choose the verification primitive (fixed-slot read vs.facets()loupe call).expectedImplementations— array of{ chainId, address, selectors? }entries. Non-semantic upgrades can be accommodated by appending the new implementation address rather than republishing.selectorsis REQUIRED whentype == "eip2535"and MUST be absent otherwise. For diamonds, the wallet enumerates the liveselector → facetmap via the diamond loupe and verifies every entry matches a declared(address, selectors)pair — catching both facet additions and selector rerouting between audited facets.context.contract.stateRefs— array of generic slot preconditions for admin parameters, state-dependent branches, custom (non-standard) proxy implementation slots, or any mutable on-chain state that bounds the displayed intent. EachStateRefhasslot,expectedValue,description, optionalmask(for packed slots), and optionalchainId/addressfor cross-contract refs. The masked comparison is(liveValue & mask) == (expectedValue & mask); bits outside the mask are ignored on both sides.expectedValueis required, making the descriptor self-verifying.Vectors not expressible via these mechanisms. Functions whose displayed intent depends on
block.timestampthresholds, block-environment values, parameter-based hidden branches, dynamic external call resolution, off-chain dependencies (oracle endpoint rotation, off-chain signing services, deployment-time library linkage), or compositional wrapping (multicall, account-abstraction batches, hooks) cannot be witnessed by this version's preconditions. Such functions MUST be omitted fromdisplay.formats; wallets fall back to opaque signing for omitted selectors. A descriptor that formats a function with intent-mutability vectors not expressible viaproxyorstateRefsis malformed and MUST NOT be attested.The auditor's filter is intent-depending, not contract-using. The test is not "does this contract use an oracle/timestamp/external call" but "does the rendered
intentor any formattedfieldsfor the function depend on a value influenced by that vector?" A function whose displayed intent is wholly parameterized by user inputs (amount, recipient, minOut, deadline) is not intent-mutable in a way the descriptor needs to express, even if the contract internally consults an oracle. A function that renders an oracle-sourced value into its displayed intent is.Wallet behavior. Wallets distinguish two failure modes: a structural
contextmismatch (wrong chain, wrong address, wrong factory) means the descriptor does not apply at all; a precondition mismatch (proxyorstateRefs) means the descriptor is the right one for this contract but its state has drifted from the audited baseline — wallets downgrade to opaque signing or warn the user. Hardware wallets satisfy the verification requirement through their companion software.EIP-7702 delegated accounts. When an EOA signs a transaction targeting another contract, its delegation is off the execution path and the targeted-contract descriptor applies normally. When an EOA signs a transaction targeting itself (smart-wallet-style), the wallet resolves the descriptor for the EOA's current delegate contract by reading the delegation indicator. Because EOA owners can re-delegate at any time, no registry can enforce delegate identity globally; wallets surface delegation status to the user.
Full design rationale (why under
contextrather than a top-level section, why a typedproxyblock earns its keep, why diamond bindings are selector-aware, whymaskexists, whyexpectedValueis required, why no descriptor-side off-chain disclosure) is documented inline in the Rationale section.What changed
ERCS/erc-7730.mdIntent trackingsection under Specification with examples: immutable contract, EIP-1967 proxy with multiple audited implementations, EIP-2535 diamond with selector-to-facet routing, admin pause flag, mapping slot (pre-computed), packed slot usingmask, proxy combined with admin state, function omission for unexpressible mutability.Intent trackingRationale subsection covering the design choices above.Intent mutabilitySecurity Considerations subsection enumerating what V2 catches and what it does not, with the "intent-depending" auditor filter and the normative omission rule.EIP-7702 delegated accountsSecurity Considerations subsection.Proxy supportupdated to route authors atcontext.contract.proxywith the righttype.assets/erc-7730/erc7730-v2.schema.jsoncontext.contract.proxyblock (typeenum +expectedImplementationsarray with optionalselectors).context.contract.stateRefsarray (StateRefwithslot,expectedValue,description, optionalmask, optional cross-contractchainId/address).The change is additive. Existing descriptors continue to validate. Descriptors without any precondition declarations are asserting that no intent-mutability vectors apply to the functions they format; auditors verify that assertion.
Out of scope
stateRefsper function). Today, per-function mutability is handled by omitting the affected function fromdisplay.formats.stateRef.expectedValue.if/then/elseschema enforcement of theselectors-required-iff-eip2535rule (currently documented prose-style).These items are tracked for a future version of the specification.
Reviewer ask
Particularly interested in feedback on:
expectedImplementationsfortype: "eip2535"is selector-aware so cross-facet rerouting within the allow-list is caught. Is the selector grain correct, or should it be facet-set-only with rerouting flagged as an auditor responsibility?