Update ERC-7730: added intent mutability specification#1738
Update ERC-7730: added intent mutability specification#1738PatrickAlphaC wants to merge 7 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. |
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, plus an optionalmetadata.intentMutabilityfree-form string for vectors that can't be witnessed on-chain. 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.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, and surface the off-chain vectors to auditors.
Design summary
The mechanism lives in three places, all OPTIONAL and additive:
context.contract.proxy— typed block for standardised upgradeable proxies:type— one ofeip-1967,eip-1822,eip-2535. 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 == "eip-2535"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.metadata.intentMutability— free-form string documenting intent-mutability vectors that cannot be reduced to a slot read or a fixed interface call: time-based branches, block-environment dependencies, parameter-based hidden branches, dynamic external call resolution, off-chain oracles, deployment-time library linkage, composition. Wallets cannot verify these claims; the trust anchor for them is auditor attestation.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 the contract's 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.Auditor obligation. An auditor reviewing a descriptor MUST verify (a) the
proxyandstateRefspreconditions are exhaustive for vectors that can be witnessed on-chain, and (b) every vector that cannot be witnessed on-chain is disclosed inmetadata.intentMutability. An attestation MUST NOT be issued while a known intent-mutability vector is undeclared.Full design rationale (why under
contextrather than a top-level section, why a typedproxyblock earns its keep over genericstateRefs, why diamond bindings are selector-aware, whymaskexists, whyexpectedValueis required, why off-chain disclosure lives inmetadata) is documented inline in the EIP's Rationale section.What changed
ERCS/erc-7730.mdIntent trackingsection under Specification with examples for: 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, off-chain disclosure in metadata.Intent trackingsubsection under Rationale covering the design choices above.Intent mutabilitysubsection under Security Considerations enumerating vectors the on-chain preconditions catch and the broader set they cannot (time, block environment, hidden parameters, dynamic external calls, cross-facet routing within an allow-list, off-chain dependencies, composition), with normative auditor obligations.Proxy supportupdated to route authors atcontext.contract.proxywith the righttype.proxyorstateRefsdeclared, demonstrating an immutable-asserting descriptor.assets/erc-7730/erc7730-v2.schema.jsoncontext.contract.proxyblock (typeenum +expectedImplementationsarray with optionalselectors).context.contract.stateRefsarray (StateRefwithslot,expectedValue,description, optionalmask, optional cross-contractchainId/address).metadata.intentMutabilityfree-form string.The change is additive. Existing descriptors continue to validate. Descriptors without any precondition declarations are asserting that no intent-mutability vectors apply to the bound contract; auditors verify that assertion.
Out of scope
stateRef.expectedValue(e.g., "value within bound", "monotonic counter"). Could be added later as a non-breaking extension; deferred until concrete demand surfaces.if/then/elseschema enforcement of theselectors-required-iff-eip-2535rule (currently documented prose-style and left to wallet/auditor enforcement).Reviewer ask
Particularly interested in feedback on:
expectedImplementationsfortype: "eip-2535"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?stateRefs.proxy.expectedImplementationsallows multiple acceptable values (for non-semantic upgrades). ShouldstateRefs.expectedValuesimilarly accept an array of acceptable values (for parameters with a known-safe band, e.g., a fee toggling between two audited rates)? Or keep it strictly point-valued and require republication?metadata.intentMutabilityas a documentation field. It lives inmetadata(notcontext) precisely because wallets cannot verify it — only auditors can. Is the auditor-obligation framing in Security Considerations strong enough, or should we move further toward requiring it to carry a structured attestation reference?selectorsis optional in the schema and the "required for eip-2535, forbidden otherwise" rule is prose. Worth a conditionalif/then/elseschema clause, or fine as prose?