Title: EIP_7702__Set_EOA_account_code
Category: EIPs

Author: vbuterin
Date: 2024-05-07T12:44:50.333Z

Add a new transaction type that adds a contract_code field and a signature, and converts the signing account (not necessarily the same as the tx.origin) into a smart contract wallet for the duration of that transaction. Intended to offer similar functionality to EIP-3074.
https://github.com/ethereum/EIPs/pull/8527

Author: SamWilsn
Date: 2024-05-07T13:01:17.043Z

Set the contract code of signer to contract_code.

Does this mean that calls back into the EOA during the transaction execute contract_code?

Should contract_code actually be initcode for more flexibility?

Author: vbuterin
Date: 2024-05-07T13:12:14.493Z

Some variations:

Should the contract_code signature also sign over the account’s nonce?
Should the contract_code signature also sign over the CHAINID?
Should the contract_code instead be an address? This would save calldata, though only a little bit of calldata because ERC-1167 proxies only take 44 bytes.
Should SSTORE inside the “temporarily contract-ified EOAs” be prohibited, like it is in EIP-5806?
Should we have initcode and not just contract_code?
Should we just add a flag to NOT set the code back to zero at the end? Thereby making this EIP also supersede EIP-5003.

Author: rmeissner
Date: 2024-05-07T13:14:32.769Z

vbuterin:

Should we have initcode and not just contract_code?


While this might add some complexity (i.e. it is not just copying code, instead it first needs to execute it) it also has the advantage that it might be “cleaner” to implement signature invalidation. I.e. in my init code I could check that this action was done within a specific timeframe, otherwise reverse, therefore invalidating the code setting signature.
Additionally this might add “out of the box” compatibility with existing tooling.

Author: rmeissner
Date: 2024-05-07T13:17:29.017Z

vbuterin:


Should the contract_code signature also sign over the account’s nonce?
Should the contract_code signature also sign over the CHAINID?



For these I assume the argumentation would be the same as for EIP-3074.
Slight difference might be on the CHAINID, as code could be seen as more “universal” (which might be a misconception tbh). Removing the dependency on the CHAINID (or making it optional), might allow for interesting use cases related to account migration.
In general I believe that this approach would allow a more complete testing of the account migration use cases, as you set the code on an address similar to 5003 and 7377.

Author: nlordell
Date: 2024-05-07T13:24:51.730Z

Should the contract_code signature also sign over the account’s nonce?


I personally felt like this was a nice feature of 3074 as it adds a “get out of jail free” card to invalidate all 7702 signatures. This can mostly be helpful in cases where the signed code has a bug and doesn’t provide functionality for disabling the code.


Should the contract_code instead be an address? This would save calldata, though only a little bit of calldata because ERC-1167 proxies only take 44 bytes.


I think if the signature is over a contract address, then you would have to also sign over a chain ID. Personally, I slightly lean towards signing code as it could allow chain ID agnostic signatures (although whether or not that is a good idea, I don’t know yet) especially given min-proxies are quite small and comparable in size to an address.


Should SSTORE inside the “temporarily contract-ified EOAs” be prohibited, like it is in EIP-5806?


It could also behave like TSTORE (in that it gets removed at the end of the transaction along with the code). But if it does behave like TSTORE, then it isn’t really any benefit to allowing SSTORE (besides maybe allowing for simpler execution code)

Author: SamWilsn
Date: 2024-05-07T13:52:00.387Z

vbuterin:


Should the contract_code signature also sign over the account’s nonce?



No. Let the contract_code handle replay protection.



 vbuterin:


Should the contract_code signature also sign over the CHAINID?



No, can check that in the bytecode.



 vbuterin:


Should SSTORE inside the “temporarily contract-ified EOAs” be prohibited, like it is in EIP-5806?



Alternatively, can the end of the transaction step be “At the end of the transaction, set the contract_code and storage of each signer back to empty.”?

Author: SamWilsn
Date: 2024-05-07T15:07:12.425Z

vbuterin:


Should we have initcode and not just contract_code?



Another argument in favour of initcode over contract_code that came up on the breakout is bypassing dumb EOA checks using extcodesize.

Author: shemnon
Date: 2024-05-07T15:18:44.363Z

What if instead of using EOA addresses, what if 7702 used a “salted” address? i.e. instead of just keccak(public_key)[-20:] it’s keccak(AUTH_MAGIC | public_key)[-20:] - that way existing EOAs won’t be impacted
That address, from its very first use, has the risks associated with eternal authorization.  That way we don’t increase the risk footprint of EOAs.

Author: taek.eth
Date: 2024-05-07T15:25:37.953Z

Might have a small DoS vector that can make a <address>.transfer()(i know this is anti-pattern, but still some contracts use this) being reverted when recipient has signed contract code that does not have receive() function
This will be up to tx.origin to post the contract code or not, but if .transfer() is being done on the execution phase of 4337, then attacker can snatch the bundle and post the bundle with recipient’s contract code, thus making the validation valid but revert on execution phase, ending up sender paying the gas but it does not achieve the behavior that sender paid for,
Also, if we look into the erc721.safeTransferFrom(), if recipient has signed the contract code before and if safeTransferFrom() is done through 4337, execution of erc721.safeTransferFrom() might fail if the recipient’s code does not have onERC721Received

Author: Ivshti
Date: 2024-05-07T15:34:13.302Z

this sounds good but how would that work if the entryPoint wants to call account.validateUserOp()?

Author: greg
Date: 2024-05-07T15:54:23.390Z

As a 3074 advocate, my first gut check is this is a really nice solution. I’d argue this is better for 5003 and 7377, which have irreversible side-effects and I would argue could lead us to another Parity wallet dilemma.
If this gets pushed through, then I’d strongly urge a standardization around which contracts are used (similar to 4337 entrypoints and 3074 invokers).


Should the contract_code instead be an address? This would save calldata, though only a little bit of calldata because ERC-1167 proxies only take 44 bytes.


Personally from a safety perspective I think this actually makes more sense, since you can have very easily verifiable ABIs/Code to sanity check against your local wallet.
–
I want to point out one thing from line 27:

at the least because eventually quantum computers will break the ECDSA that EOAs use)

(happy to move this conversation elsewhere)
I don’t think this is an overly sound argument. If ECDSA breaks we’re doomed beyond belief, and realistically before we start using this as a counter-point we need to actually have a plan (or the research) showing how were moving towards quantum safe curves ASAP. I’d assume most smart accounts are using ECDSA as a majority set of the signers, so that doesn’t save us either.

Author: ch4r10t33r
Date: 2024-05-07T16:13:39.070Z

vbuterin:

Should we just add a flag to NOT set the code back to zero at the end? Thereby making this EIP also supersede EIP-5003.


If the code is not reset, would the private key controlling the account become ineffective (similar to 7377)? If so, how would one initiate transactions from that smart account? Always with the new transaction type?

Author: Arachnid
Date: 2024-05-07T16:15:49.787Z

I proposed something similar in 2020; the comments from then may provide some useful food for thought: "Rich transactions" via EVM bytecode execution from externally owned accounts

Author: derek
Date: 2024-05-07T16:17:12.164Z

Regarding whether to sign over the account’s nonce:


As I argued in the 3074 call, signing over the account’s nonce would invalidate most of the popular use cases of AA that we are seeing in the 4337 ecosystem today, particularly alternative singers (e.g. attaching a passkey to your EOA) and transaction delegation (creating a session key for a DApp).


@yoavw had a proposal for signing over a user-picked maxNonce instead.  I think this proposal is impractical from a UX perspective, since it’s not clear how the user is supposed to pick a sensible maxNonce.  However, I like how it basically gives the user a way to opt out of in-protocol revocation.  So the user could just set maxNonce to 2^64 if they don’t want to accidentally revoke the signature, and then they’d rely exclusively on the contract code for revocation.


I do think there’s another proposal worth considering: nonceManager.  This was first described here and here.  Basically, we let the user pick a nonceManager, and it’s the nonceManager’s nonce that we sign over.


Notably, the nonceManager can be a counterfactually deployed smart account owned by the user’s EOA, so that when the user does want to revoke, they’d send a transaction with the smart account.  And they don’t actually have to pay gas to deploy the smart account unless they want to revoke, since the account could be counterfactually deployed.
Personally, I think it’s OK to just ignore nonce altogether in the sig, but if people are not comfortable with that (for the same reason that made people add nonce to 3074), then I think either the maxNonce proposal or the nonceManager proposal could work, though I prefer nonceManager since, unlike the maxNonce proposal:

It gives the user a way to selectively revoke signatures without accidentally revoking anything.  With maxNonce, you always have to revoke everything within the range.
Unlike the maxNonce proposal, there’s no UX issue of picking a max nonce.

Author: protolambda
Date: 2024-05-07T17:15:45.442Z

I support this EIP wholeheartedly. This is incredibly useful, as it looks like it essentially supports atomic bundling / composability of user-ops in protocol. This allows a lot of block-building policy protocols to really improve user-experience and support things like just-in-time data without changing the state trie in-between transactions.
Clarifying in the EIP when the TSTORE/TLOAD is shared during tx execution would be great. Setting it globally for the transaction, rather than per user-op, avoids the need to rely on account-code presence to persist data between user-ops. The 3074 comparison hints at it, but it is not entirely clear.

Author: adamegyed
Date: 2024-05-07T17:22:04.226Z

I am generally in favor of this approach to gradually introducing AA features to EOAs. I have one point I’d like to make, and a suggested implementation path.
I think it is important for this proposal to support both:

Re-using the signature from an EOA across multiple transactions, using the contract code to enforce signature checks and uniqueness.
Allow EOAs to revoke existing signatures over code.

Point 1 is critical for AA use cases around alternative transaction validity conditions, which includes other cryptographic schemes like passkeys, multisig capabilities, and permissions. Point 2 is critical to allow for “upgrading” account’s code implementation, without simultaneously allowing the old code to also be assumed. It is to prevent the “perpetual signature” risk that was identified with EIP-3074.
My proposal for how to accomplish this is to introduce a new, parallel nonce field for accounts, distinct from the existing transaction nonce. Name TBD, calling it “code assumption nonce” for now.
EIP-7702 transactions could require the EOA signature to be over the “code assumption nonce”, rather than their transaction nonce, to start an EOA assuming code. Of course, each transaction using this format would still increment the respective account nonces, ensuring unique transaction hashes.
Multiple outstanding signatures could be placed over the same “code delegation nonce”, allowing different pieces of code to be assumed in different transactions.
Accounts could opt to invalidate outstanding “code delegation nonces” by signing a 7702 signature over a magic value, such as empty code or code only containing 0xFE (invalid opcode), indicating they intend to increment the nonce and invalidate all outstanding 7702-enabling signatures.
I see there are two other proposals for how to accomplish this (or something similar), and I want to address why I don’t think they are the best choice forward.

One idea is to sign over a max nonce. I believe this provides a clumsy user experience for any form of AA-based transaction automation, forcing the user to guess how many times contract automation would happen, and having to either sign very far in advance or regularly re-sign to bump the nonce. Additionally, it would require more control over how to bump nonces to invalidate signatures, likely requiring the protocol to allow bumping the nonce by more than one at a time. This introduces unneeded complexity into nonce management that the EVM must bear, rather than contracts themselves.
Another idea is to fully delegate nonce control to an external contract (the “nonce manager”), and introduce either code or an address to the contract into the 7702 transaction type as a field. I believe this to be too far in the other direction, enshrining too much application-specific logic into the transaction type than what is needed, thus making it unnecessarily complex. A “code assumption nonce” still allows for implementation-dependent nonce control, such as to track nonces for session keys or secondary signers to the account, within the code the EOA is assuming.

By keeping 7702 code assumption tracked in a separate nonce from individual transaction nonces, we can provide both customizable nonce behavior, and the ability for EOAs to manually exit and/or upgrade their code assumption behavior.
EDIT: I previously misunderstood how the max nonce field would work. If the EOA nonce is not incremented when used to assume code in a transaction while not being tx.origin, then using max nonce fields for the purposes of allowing alternate txn validity conditions is sufficient and doesn’t have the UX pitfalls I previously imagined. I’m keeping the proposed idea up here for posterity.

Author: wjmelements
Date: 2024-05-07T20:26:50.232Z

Instead of setting a constant for the code size costs, it should be equal to the calldata cost plus the eip-3860 gas adjustment used for create txs, to account for the jumpdest validation.

Author: Michaels
Date: 2024-05-07T21:28:37.079Z

I think another valid question is if selfdestruct opcode should be prohibited. If not, would it mean a gas refund  or incur more gas? Also that mean that the signers eth balance is drained to the selfdestruct argument?

Author: Michaels
Date: 2024-05-07T22:21:34.591Z

Taking the bytecode would be better imo as it doesn’t require the contract (if an address is required) to already be deployed in a previous tx. In most cases, a proxy to an existing 4337 code would be used but flexibility would be good too and not needing the code to be predeploted to an address beforehand is helpful


No, storage opcodes should not be prohibited. It (all written storage slots) should however be cleared at the end of the transaction and its gas costs be the same as TLOAD and TSTORE since they’d then behave similarly.


Yes. Init code rather than runtime code would be helpful for more specific and custom instances

Author: dror
Date: 2024-05-07T23:09:36.755Z

shemnon:

that way existing EOAs won’t be impacted


The idea of this EIP is to let existing EOA accounts run “as if” they have code.
Mapping to different addresses doesn’t let you work with existing accounts, which defeats the purpose

Author: dror
Date: 2024-05-07T23:18:53.239Z

vbuterin:

Should the contract_code signature also sign over the account’s nonce?


Yes, the signature should include the nonce - unless another revocation mechanism is used. If a user did happen to sign a rogue contract-code, there MUST be a way to disable it, even if the rogue contract doesn’t support such revocation.



 vbuterin:

Should the contract_code instead be an address


Instead of providing the code in each transaction, we could instead provide an address, and CODECOPY the code from there.
Its true that small static proxies are only 44 bytes - but what if we want to use another proxy? adding yet another small static proxy just to reduce the TX size seems a bad solution.

Author: dror
Date: 2024-05-07T23:21:04.781Z

vbuterin:

Should we have initcode and not just contract_code?


Sounds a bit weird to run an initcode on each transaction…
Also, as per my previous comment, if we copy the code from another contract - we can’t provide an initcode, since it isn’t on-chain.

Author: yoavw
Date: 2024-05-07T23:38:00.061Z

vbuterin:


Should the contract_code signature also sign over the account’s nonce?



nonce is a bit restrictive but we do need a revocation method in the protocol. Either the maxNonce+bumpNonce(uint32) I proposed, or nonceManager that @derek proposed.
Both would serve that purpose.  The trade off is that the former is less granular (revoke all the past sigs) but doesn’t increase the cost for normal transactions, whereas the latter is granular but adds gas cost to every transaction (accessing another cold account).
Another implication of nonceManager is cross-dependency between addresses. A single nonceManager could invalidate sigs from multiple accounts, so the mempool won’t be able to safely accommodate many transactions that share nonceManager even if the EOAs are different.  This might introduce a censorship vector: if a user is known to use a certain nonceManager, an attacker can send a lot of transactions from other EOAs specifying the same nonceManager with low priority fee so they stick around in the mempool for a while.  The user won’t be able to propagate a transaction with that nonceManager.



 vbuterin:


Should the contract_code signature also sign over the CHAINID?



Not strictly necessary, unlike in 3074.  With invokers we needed it because a different contract could be deployed to the same address on other chains.  With 7702 the code itself can (and should) check chainid before doing anything else.  It enables cross-chain transactions when the code supports them explicitly.
This is already the case in 4337 accounts.  The protocol makes chainid enforced by default since EntryPoint calculates userOpHash with chainid, but there’s a way to explicitly “opt out”:  The account’s validateUserOp receives the userOpHash and by default it checks a signature on it, but it doesn’t have to.  I’ve seen a case where a cross-chain account ignores userOpHash for certain UserOp.calldata[0:4] (a chain-aware function), calculates a different hash that excludes chainid and validates that.  The function itself receives a list of chainids and enforces them.



 vbuterin:

Should the contract_code instead be an address?


We could, but there’s a trade off here, and I lean on not making it an address.  It would bring back the issue of potentially different implementations on different chains, e.g. a malicious version deployed at the same address on some future chain.  If we make it an address then we’ll need to include chainid.  I’d hate to do that after @SamWilsn and I finally agree on something 



 vbuterin:


Should SSTORE inside the “temporarily contract-ified EOAs” be prohibited, like it is in EIP-5806?



I think so, but not for the commonly discussed reason.  I’m less concerned about storage collision when the account is still EOA - the wallet should be aware of code it delegates to, just like a diamond proxy.  The bigger reason is potential rugpulls when combined with (6) (setting permanent code).  E.g. create a legit-looking Safe after injecting some shadow signers to the storage via 7702 transactions.  Trusting an account that was deployed via (6) will require going through all the past transactions if they set any storage.  If any was set, it may be impossible to know what it means for the new implementation, e.g. maybe it’s some keccak that maps to owners[attacker].
A safer way to handle storage is by calling a storage contract associated with the current implementation.  The storage contract maintains per-EOA storage via a mapping, so it can be accessed during 4337 validation.  If the account uses different implementations for different transactions, they use different storage contracts and therefore don’t interfere with each other.  And if the code is set permanently at some point, the newly-set implementation already knows how to access the previously set slots it wrote to.



 nlordell:

It could also behave like TSTORE (in that it gets removed at the end of the transaction along with the code).


Then the code should just use TSTORE. Otherwise it may have unintended consequences. Consider an account that temporarily uses Safe (yes, Safe is my favorite example - shoutout @rmeissner ).  If it uses the current Safe implementation rather than one with an external storage contract like the one I described above, then it’ll increment its own nonce in storage but the nonce gets reset at the end of the transaction - resulting in a replay.  If SSTORE behaves like TSTORE, the contract should know it.  The protocol should keep Safe safe.



 SamWilsn:

No. Let the contract_code handle replay protection.


Then if you ever sign one that doesn’t implement revocation properly, you’re stuck with it forever.  I think the two options above (maxNonce and nonceManager) solve this problem without blocking any use case.  The contract can handle its own replay protection but the user still has revocation ability.



 SamWilsn:

No, can check that in the bytecode.


This time we agree on it 



 SamWilsn:

Alternatively, can the end of the transaction step be “At the end of the transaction, set the contract_code and storage of each signer back to empty.”?


Risky.  See unintended consequences above. It storage is ephemeral, the contract should be aware.



 SamWilsn:

Another argument in favour of initcode over contract_code that came up on the breakout is bypassing dumb EOA checks using extcodesize.


and then we discussed the trade off: not being able to support callbacks because solidity contracts won’t call an address with zero codesize.



 shemnon:

What if instead of using EOA addresses, what if 7702 used a “salted” address?


Safer but probably not what the authors intended, since the transacting address is no longer the EOA that holds the assets.  E.g. to batch approve+transferFrom you’d have to first transfer your assets to this shadow address in a separate transaction, breaking the probably-most-popular use case for this EIP.



 taek.eth:

This will be up to tx.origin to post the contract code or not, but if .transfer() is being done on the execution phase of 4337, then attacker can snatch the bundle and post the bundle with recipient’s contract code, thus making the validation valid but revert on execution phase, ending up sender paying the gas but it does not achieve the behavior that sender paid for,


I’m not sure I understand the attack.  The user controls the contract that will be in the account during the UserOp.  This includes both validateUserOp and receive() (which indeed every implementation should have).  How can the attacker run a UserOp that has the proper validateUserOp but not the receive()?  Can you elaborate on the attack flow?



 taek.eth:

execution of erc721.safeTransferFrom() might fail if the recipient’s code does not have onERC721Received


The same is true for ERC-4337 accounts.  Any reasonable implementation should have it, unless it only calls contracts that are known not to callback.
But you’re highlighting an important topic: we’ll need a good best-practices document for implementations.  Which callbacks to support, how to handle storage, etc.  Might even make sense to include it as a section in the EIP, but @SamWilsn and @matt are the experts on what belongs in the EIP.  Do these best practices belong in the EIP?



 greg:

similar to 4337 entrypoints


Just correcting a common misconception here: There are no “4337 entrypoints” (plural).  EntryPoint is the implementation of the 4337 protocol itself, and not an entity in the 4337 ecosystem.  It is just implemented as a singleton contract because it’s an ERC rather than EIP.  And RIP-7560 has no EntryPoint contract because the logic is moved to the protocol.



 greg:

Personally from a safety perspective I think this actually makes more sense, since you can have very easily verifiable ABIs/Code to sanity check against your local wallet.


If the wallet itself signs the code, it can also verify ABIs.  And if we make it an address rather than code, it brings back the chainid issue above.



 ch4r10t33r:

If the code is not reset, would the private key controlling the account become ineffective (similar to 7377)? If so, how would one initiate transactions from that smart account? Always with the new transaction type?


The key must become invalid.  The account becomes a smart account.  Hopefully an ERC-4337 smart account that you can send UserOps to via the AA mempool, but that’s up to the implementation.

Author: wjmelements
Date: 2024-05-08T00:00:13.311Z

For situations like UniswapV3 callbacks where the msg.sender is called, this solution is strictly superior to 3074, where they wouldn’t have code to handle the callback.

Author: taek.eth
Date: 2024-05-08T00:11:14.861Z

yoavw:

I’m not sure I understand the attack. The user controls the contract that will be in the account during the UserOp. This includes both validateUserOp and receive() (which indeed every implementation should have). How can the attacker run a UserOp that has the proper validateUserOp but not the receive()? Can you elaborate on the attack flow?


it’s more of an recipient issue than a sender issue,
“if recipient signed a code that does not have receive function, sender might face DoS if they try to send assets.”
1.“eoa A” sign this code, use it one time, valid v,r,s becomes propagated with 7702 tx type
contract Hello {
    function foo() external {
        emit Bar();
    }
}


4337 wallet B wants to send eth to “eoa A” through this code and creates userOp

function hello(address _to) external{
    _to.transfer(3);
}


bundler picks up the userOp and make bundle
attacker X snatches the bundle and send bundle tx with (v,r,s) obtained on step 1
_to.transfer(3) fails because Hello function does not have receive() function, B pays for the userOp so X does not have any risk. A does not risk any asset, but they do have risk of not receiving eth from 4337 accounts.

this applies same to erc721/erc1155
1.“eoa A” sign this code, use it one time, valid v,r,s becomes propagated with 7702 tx type
contract Hello {
    function foo() external {
        emit Bar();
    }
}


4337 wallet B wants to send erc721/erc1155 through this code and creates userOp

function sendNFT(address _to) external{
    _to.safeTransferFrom(msg.sender, _to, 3);
}


bundler picks up the userOp and make bundle
attacker X snatches the bundle and send bundle tx with (v,r,s) obtained on step 1
sendNFT fails because safeTransferFrom calls onERC721Received when the code size is larger than 0, but onERC721Received does not exist on contract Hello

The issue here is that contract code that has been signed once can be used indefinitely to DoS the receive of eth/erc721/erc1155 when sender account is 4337 account

Author: yoavw
Date: 2024-05-08T00:20:32.446Z

taek.eth:

The issue here is that contract code that has been signed once can be used indefinitely to DoS the receive of eth/erc721/erc1155 when sender account is 4337 account


I understand what you mean.  This could happen.  But the issue is that EOA A signed something it shouldn’t have - a replayable that sets a bad implementation (with no receive()).  If it took care to only sign implementations that follow the best practices (which we still need to write), it should be safe.

Author: yoavw
Date: 2024-05-08T00:34:28.898Z

This EIP has other interesting implications.  It makes counterfactual contracts cheap to use: they can be used on-chain without ever deploying them.  Create the contract code, then generate a “nick’s method” signature for it to create the “EOA” address.  Reuse on-chain whenever the contract is needed, never actually deploy it.
Make America Plasma great again!

Author: SamWilsn
Date: 2024-05-08T01:01:47.720Z

yoavw:

Risky. See unintended consequences above. It storage is ephemeral, the contract should be aware.


You’ve convinced me.



 yoavw:

Might even make sense to include it as a section in the EIP, but @SamWilsn and @matt are the experts on what belongs in the EIP. Do these best practices belong in the EIP?


It’s a difficult question. Best practices should evolve over time, but EIPs all eventually have to become immutable. I’d put a list of problems these contracts need to be aware of in Security Considerations, but it’ll never be exhaustive.



 Ivshti:

this sounds good but how would that work if the entryPoint wants to call account.validateUserOp()?


Once the initcode finishes executing, the EOA will have deployed code, and will be able to receive callbacks.



 derek:

I do think there’s another proposal worth considering: nonceManager.


How is this better than the signed bytecode calling into the nonceManager early in its execution?



 Michaels:

I think another valid question is if selfdestruct opcode should be prohibited.


Self-destruct in one of these EOAs should follow the rules in EIP-6780 (basically just send all ether without executing any bytecode.) I don’t see any reason to prohibit it.

Author: SamWilsn
Date: 2024-05-08T01:42:39.590Z

Pull request to prohibit SSTORE: Add EIP: Set EOA account code for one transaction by SamWilsn · Pull Request #8528 · ethereum/EIPs · GitHub

Author: yoavw
Date: 2024-05-08T01:44:49.767Z

vbuterin:


Should we have initcode and not just contract_code?



Following a discussion with @SamWilsn , no, that would break integration with 4337 or any other system that separates validation/execution.  The 7702 data becomes a part of the propagated UserOp and affects validation.  If bundles execute this initcode before calling handleOps, and initcode reverts, then the UserOp may become invalid.  E.g. require(block.timestamp<something) in initcode would enable mass invalidation and DoS the AA mempool.
If we add initcode, it would have to be pure.  It would need to be simulated, ERC-7562 rules would have to be applied, it wouldn’t be able to call other contracts, use opcodes like GAS, etc.  It becomes a part of the validation code, that happens to run outside the 4337 validation function so we can’t apply gas limits, etc.  Making this mempool-compatible would be tricky and probably not worth the effort.

Author: yoavw
Date: 2024-05-08T01:47:29.899Z

SamWilsn:

How is this better than the signed bytecode calling into the nonceManager early in its execution?


It’s better because the bytecode might not call it.  Revocation becomes an implementation feature rather than a protocol feature.  If you ever sign an unrevocable implementation (back when you were using a bad wallet before you switched to your current one), it has access to your account forever.

Author: SamWilsn
Date: 2024-05-08T01:53:35.891Z

And your nonceManager might not work. If you can verify a nonceManager, you can verify your contract_code.

Author: yoavw
Date: 2024-05-08T02:12:49.540Z

I agree that’s a risk.  And I pointed out another one above.  maxNonce seems safer and cheaper (albeit less granular).  I don’t think we need that granularity - just set it to 1000000 and most likely you’ll never have to think about it again unless a bug is discovered in something you signed.

Author: derek
Date: 2024-05-08T03:19:53.944Z

How is this better than the signed bytecode calling into the nonceManager early in its execution?

To be clear, my preference is to leave nonce out of signature altogether.  I’m simply bringing up nonceManager as a compromise if people really want nonce inside the signature.  In that case, I think nonceManager is the best proposal given the reasons I listed above.

Author: yaonam
Date: 2024-05-08T03:24:32.883Z

yoavw:

because a different contract could be deployed to the same address on other chains.


What if we signed over the code_hash in addition to the contract address? This could be a nice compromise between the entire code and just the address, assuming the hash isn’t too difficult to check.

Author: hoshiyari420
Date: 2024-05-08T03:30:47.639Z

How should native token(ETH) fallback and receive functionality work in EIP-7702 contract_code? Should it be allowed to break the flow of transaction as eventually it’s an EOA?

Author: ducthotran2010
Date: 2024-05-08T07:01:06.582Z

rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, data, access_list, [[contract_code, y_parity, r, s], ...], signature_y_parity, signature_r, signature_s])

I’m curious why we do not include a specific amount field in this proposal, considering it permits interactions with any destination accounts but doesn’t directly allow transferring native tokens when initiating the transaction. Could the intended transfer functionality still be achieved through self-invoking
and including CALL opcodes in the bytecode? If so, it seems the destination field might be unnecessary.

Author: dror
Date: 2024-05-08T08:04:30.027Z

My suggestion for code is to specify contract address to copy from, but sign the code.
This way we save repeatedly copying the code in each transaction, while still preventing cross-chain risks.
The benefits:

smaller per-transaction calldata
clearer message that it is a shared implementation, not user-specific
easier for external tools (e.g. look up same implementations, view published/verified source code)

Author: dror
Date: 2024-05-08T08:17:26.732Z

Some unintended consequence of eip-7702:
Consider I have an EOA and eip-7702 to call a service that uses an eip-1363 token, and my account implements onTransferReceived() logic.
If I trigger a transaction that makes the service call this callback, it gets executed.
But if some other tokens are sent in another transaction, the callback doesn’t get executed.
Moreover, the caller of the transation may decide if he wants my callback to get executed, by including my contract_code and signature  in his transaction, or not.
The moral is that contract_code developers should be wary of the fact that they can’t control if and when such callbacks are called.

Author: ankurdubey521
Date: 2024-05-08T08:46:24.065Z

yoavw:

Another implication of nonceManager is cross-dependency between addresses. A single nonceManager could invalidate sigs from multiple accounts, so the mempool won’t be able to safely accommodate many transactions that share nonceManager even if the EOAs are different. This might introduce a censorship vector: if a user is known to use a certain nonceManager, an attacker can send a lot of transactions from other EOAs specifying the same nonceManager with low priority fee so they stick around in the mempool for a while. The user won’t be able to propagate a transaction with that nonceManager.


One way to solve this issue (at the expense of increased complexity) is to enforce that the nonceManager address is associated with the EOA at the mempool level. If the nonceManager is a contract and its address is derived from the EOA address by perhaps using the EOA as a salt to CREATE2 (or similar), a proof for nonceManager address derivation which includes the EOA can be included with the transaction to prove that the nonceManager is associated with the EOA.
While this does increase complexity, I don’t think these details should be included in the EIP and can perhaps be included in ERC7562.

Author: greg
Date: 2024-05-08T10:09:04.369Z

One way to solve this issue (at the expense of increased complexity) is to enforce that the nonceManager address is associated with the EOA at the mempool level

I’d argue we don’t want to add more things into the mempool.



 dror:

Some unintended consequence of eip-7702:


Doesn’t this EIP also break an invariant for code not changing at an underlying address? If you have logic today that performs EXTCODEHASH, and store those results (in a mapping against address) you have the possibility of having an infinite number of results.

Author: ankurdubey521
Date: 2024-05-08T10:16:58.493Z

yoavw:

nonce is a bit restrictive but we do need a revocation method in the protocol. Either the maxNonce+bumpNonce(uint32)


Assuming that the mempool allows submitting transactions with multiple nonces, wouldn’t bumpNonce(k) allow invalidating all transactions between nonces c and c+k present in the mempool, where c is the current nonce of the EOA? Does this potentially qualify as a mass-invalidation attack vector?

Author: peersky
Date: 2024-05-08T12:22:43.080Z

Do I understand correct that in order to execute smart contract code from EOA via 4337, the TX type would set contract code and hence create(initCode) part of 4337 would not be needed to be called (code already exists)?

Author: dror
Date: 2024-05-08T13:07:32.887Z

This EIP is to give some AA functionalities to EOAs.
Yes, EOA doesn’t have code, and doesn’t deploy it - the transaction is executed “as if” the code is there.
This is an interim solution, and by no means a replacement for a full-fledged AA solution.
From security perspective, you’re at a much better position if you deploy an ERC4337 account, rather than trying to use an EOA using this EIP-7702 transaction.

Author: PatrickAlphaC
Date: 2024-05-08T14:24:06.231Z

Should we hold off including 3074 to chat about this more? Or are we thinking this will be mainly additive with 3074?

Author: n4ss
Date: 2024-05-08T17:02:20.602Z

I strongly vote for 3074 to also be included, ourselves and many other embedded wallet providers simply want to remove friction with gas sponsorship & transaction without increasing costs.
For context, most / all embedded wallets already have a relatively high level of trust delegated from their customers or end users so 3074 works out perfectly. 3074 remains the perfect next step for all the wallets that rely on 2771 meta transactions to move to protocol-native solutions without the requirement to whitelist a forwarder, and for simpler solutions that don’t require an entire paymaster infra.
Costs are significantly higher for 7702 compared to 3074 once you add revocation, chain verification and other things which is the highest worry for the majority of the ecosystem.
I want to highlight that incentive are very tricky in the conversation because several people chiming in here are building businesses that charge fees on sponsored gas so higher gas fees are better business-wise. But for any application, protocol, or business that don’t make money off of sponsored gas: it’s a net negative.
Separately, 3074 is a lot simpler to support for many of us who may just want to maintain an invoker without much more involved work.
Finally, I do think that users should be able to choose on a per-transaction basis which path they prefer between 3074 & 7702 as the properties are very different in practice:
• 3074: much cheaper, simpler, must be more trusted
• 7702: more expensive, more complex, trust delegation scales with complexity

Author: SamWilsn
Date: 2024-05-08T18:24:27.230Z

That’s quite interesting! If contract_code is deployed directly, then even if it checks chain id or nonce, an attacker could bundle any of your previous signatures to mess with token receipts for a particular bundle.
I think initcode would prevent this? The initcode could revert, making the deployment fail.

Author: dror
Date: 2024-05-08T20:28:40.304Z

SamWilsn:

I think initcode would prevent this?


The root cause is not the initialization, so adding initcode won’t help here.
I only mentioned it as an issue that an EIP-7702-wallet should be aware of the fact, and not attempt to do anything special within this callback.
The only mitigation is have persistent code - that is, deploy a full-fledged AA contract at that address.

Author: SamWilsn
Date: 2024-05-08T22:22:26.401Z

The issue I’m raising is a bit different.
Consider this (somewhat) simple example:
// XXX: Unsafe; example only.
contract NonceStore {
    mapping (address => uint256) public nonces;

    function takeNonce(uint256 expected) external {
        require(expected == nonces[msg.sender]++);
    }
}

contract Ephemeral {
    NonceStore constant public nonceStore = NonceStore(address(0x01));

    function approveAndCall(
        uint256 nonce,
        ERC20 token,
        uint256 wad,
        address spender,
        bytes memory data
    ) external {
        nonceStore.takeNonce(nonce);
        token.approve(spender, wad);
        (bool a,) = spender.call(data);
        require(a);
        token.approve(spender, 0);
    }
}

Assume that NonceStore is previously deployed at address 0x01, and I’m using Ephemeral in a 7702 transaction. Works great, and my approve-and-transfer goes through fine. It even has replay protection!
Now imagine some time has elapsed, and you want to send me an an ERC-1363 (or ERC-1155 or whatever) token from your own 7702-enabled account.
A malicious person could take my old Ephemeral signature and put it in front of your signature in the 7702 bundle. Obviously the nonce check will fail, but because my EOA now has code in it, the receive callbacks will fail, and the bundler can cause your transaction to fail.

Author: wjmelements
Date: 2024-05-08T23:39:02.399Z

The substituted user accounts should be started warm for the purposes of eip-2929.

Author: Amxx
Date: 2024-05-09T00:27:13.527Z

FYI: I believe some restriction should apply to protect the EOA and the mempool against nonce increasses
https://github.com/ethereum/EIPs/pull/8538

Author: SamWilsn
Date: 2024-05-09T01:39:44.443Z

Amxx:

protect the EOA


Is this not analogous to handing a signed (but unbroadcast) transaction to someone, and now that someone can also bump your nonce?



 Amxx:

protect […] the mempool


geth (and I assume other clients) protect against similar attacks by limiting the number of pending transactions per account.
Is using 7702+CREATE/CREATE2/etc. worse than invalidating pending transactions using a private mempool and a number of normal transactions?

Author: yoavw
Date: 2024-05-09T02:58:25.929Z

yaonam:

What if we signed over the code_hash in addition to the contract address?


That would be fine.  Doesn’t matter if it’s the code or its hash, just as long as it’s not just an address.  It also makes it more efficient since the hash doesn’t need to be in the transaction itself.  It can be read on-chain and used for verifying the transaction.  I’m in favor of doing that.

Author: yoavw
Date: 2024-05-09T02:59:49.174Z

hoshiyari420:

How should native token(ETH) fallback and receive functionality work in EIP-7702 contract_code?


The contract would have to implement these functions.  During a 7702 transaction the account is not an EOA, it’s a temporary contract.  See “best practices” above.

Author: yoavw
Date: 2024-05-09T03:00:58.341Z

I agree.  That’s what @yaonam suggested and I think it’s the right trade off.  I support replacing contract_code with an address as long as the signature covers the contract’s code (which doesn’t need to appear in the transaction since it’s on-chain).  And then we still don’t need chainid because it ensures the code is the same on every chain.
@SamWilsn - this is in contrast to what I said before about the address, so I’m pointing it out here.  Transaction becomes smaller (only an address), cross-chain functionality is preserved, and so is safety (due to the code hash verification).  WDYT?

Author: yoavw
Date: 2024-05-09T03:02:05.900Z

dror:

The moral is that contract_code developers should be wary of the fact that they can’t control if and when such callbacks are called.


Right.  7702 is not a replacement for account abstraction.  If you need the account to have the same logic when others interact with it, use a smart account.  7702 is meant to bring some of the benefits to EOA, not every benefit.  Still a good trade off for many users.

Author: yoavw
Date: 2024-05-09T03:06:13.278Z

ankurdubey521:

One way to solve this issue (at the expense of increased complexity) is to enforce that the nonceManager address is associated with the EOA at the mempool level. If the nonceManager is a contract and its address is derived from the EOA address by perhaps using the EOA as a salt to CREATE2 (or similar), a proof for nonceManager address derivation which includes the EOA can be included with the transaction to prove that the nonceManager is associated with the EOA.


You’re proposing a way to make NonceManager “associated” with the EOA in the ERC-7562 sense, much like associated storage.  That would work but it means that every EOA needs to actually deploy a contract to be used as its NonceManager.  If you’re already deploying a contract, why not just deploy a smart account and get the full benefits of AA?



 ankurdubey521:

While this does increase complexity, I don’t think these details should be included in the EIP and can perhaps be included in ERC7562.


It would have to be known to the protocol, and in fact ERC-7562 doesn’t need to know about it. Revocation is a protocol feature, not a 4337-related feature.  The protocol needs to stop respecting a signature if it has been revoked, which requires it to know about NonceManager.  This does complicate the EIP and I’m still not sure it brings much benefits beyond maxNonce - which keeps things as simple as possible while supporting protocol-level revocation.

Author: txgyy
Date: 2024-05-09T03:11:52.623Z

Flags for what to sign over and whether to keep code at the end.


If EIP7702 has already been implemented, the cost of adding a new algorithm isn’t high.


The risk of permanently upgrading an EOA to a CA is significant (as EOAs carry historical baggage), but addresses generated by algorithms like secp256r1 are not EOAs, so permanently setting code carries no additional risk.


People need a more stable way to ensure deterministic deployments.


For example:

0x00: Temporary upgrade And secp256k1
0x10: Permanent upgrade And secp256k1
0x01: Temporary upgrade And secp256r1
0x11: Permanent upgrade And secp256r1
…

Or, if you think supporting secp256r1 isn’t necessary, just determine the contract address using the eoa+1 method.
The higher-level abstraction of upgrading an EOA to a CA is verifying an address and setting code for it. I’m sure someone will use your protocol to deploy contracts; otherwise, we should better support this operation at the protocol level.

Author: SamWilsn
Date: 2024-05-09T03:40:59.640Z

yoavw:

@SamWilsn - this is in contrast to what I said before about the address, so I’m pointing it out here. Transaction becomes smaller (only an address), cross-chain functionality is preserved, and so is safety (due to the code hash verification). WDYT?


Hm, that means you need to have the code you want to run already deployed on chain? A tiny bit less flexible I suppose, but I’m not strictly opposed.
From a quick estimate, the smallest reasonable proxy is what, like 50 bytes? So we’d be saving 30 bytes per transaction. We’re sure that’s worth it?

Author: yoavw
Date: 2024-05-09T03:54:19.663Z

greg:

Doesn’t this EIP also break an invariant for code not changing at an underlying address? If you have logic today that performs EXTCODEHASH, and store those results (in a mapping against address) you have the possibility of having an infinite number of results.


It does, but why would a contract store a mapping of accounts’ codehashes when EXTCODEHASH is much cheaper than storage?  Besides, making assumptions on user account’s behavior based on code hash would almost always be unsafe because most users use proxies and could change the implementation.



 ankurdubey521:

Assuming that the mempool allows submitting transactions with multiple nonces, wouldn’t bumpNonce(k) allow invalidating all transactions between nonces c and c+k present in the mempool, where c is the current nonce of the EOA? Does this potentially qualify as a mass-invalidation attack vector?


Yes, and my maxNonce proposal addresses that.  Currently 63 pending transactions are allowed per EOA.  Bumping the nonce should be expensive enough to compensate for that.  Such invalidation is currently possible via replace-by-fee, sending 63 transactions and then replacing the first one at +10% cost to a transaction that drains the eth from the account.  As long as bumping is at least as expensive as that, it doesn’t introduce a new issue.  And since it’s a rare operation (you only do it when switching wallets or when a vulnerability is found in something you previously signed), it’s fine to make bumping expensive.



 SamWilsn:

A malicious person could take my old Ephemeral signature and put it in front of your signature in the 7702 bundle. Obviously the nonce check will fail, but because my EOA now has code in it, the receive callbacks will fail, and the bundler can cause your transaction to fail.


The 4337 integration of 7702 will prevent this by including UserOp.sender’s codehash in the signature verification.  If someone tries to bundle your UserOp while replacing the account implementation with something else you previously signed, it’ll fail validation.  Therefore it won’t propagate through the AA mempool, and if a bundler attempts to do it directly it’ll just result in an on-chain bundle revert at the attacker’s expense without achieving anything.  Your UserOp stays in the mempool and another bundler will include it properly.
We’ll post something about how 7702 can be integrated into 4337 soon.  I think it can be fairly lightweight and solve this kind of issues.



 SamWilsn:

Hm, that means you need to have the code you want to run already deployed on chain? A tiny bit less flexible I suppose, but I’m not strictly opposed.


Yes, I thought that’s what people here wanted to do when proposing using an address instead of code.  From security perspective the two options are equivalent as long as the signature covers the actual code.  Just a different trade off: one time deployment of an implementation that is probably shared by many users, and in exchange we make all 7702 transactions cheaper due to using just 20 bytes.



 SamWilsn:

From a quick estimate, the smallest reasonable proxy is what, like 50 bytes? So we’d be saving 30 bytes per transaction. We’re sure that’s worth it?


I don’t have a strong opinion in which one is better, as long as the signature covers the code, but I think others in this thread are concerned about this cost.  I have to say I do like the flexibility of including actual code that the wallet can change without deploying another contract.  It enables some use case that would be expensive otherwise, for things like intent solvers.  Maybe it’s worth the extra ~30 bytes cost.

Author: SamWilsn
Date: 2024-05-09T04:14:53.047Z

yoavw:

The 4337 integration of 7702 will prevent this by including UserOp.sender’s codehash in the signature verification. If someone tries to bundle your UserOp while replacing the account implementation with something else you previously signed, it’ll fail validation. Therefore it won’t propagate through the AA mempool, and if a bundler attempts to do it directly it’ll just result in an on-chain bundle revert at the attacker’s expense without achieving anything. Your UserOp stays in the mempool and another bundler will include it properly.


I’m not sure I follow. So the destination of the transaction would be responsible for checking the codehash of each signer? Against what?
I have to apologize again for not fully understanding all the 4337 specifics.
The scenario I’m worried about would be a bundler adding an item to the transaction without adding it to the bundle, so something is deployed at the token recipient’s address, even though the token recipient has not submitted a UserOp recently.

Author: yoavw
Date: 2024-05-09T04:31:14.527Z

SamWilsn:

I’m not sure I follow. So the destination of the transaction would be responsible for checking the codehash of each signer? Against what?


Not the destination of the transaction.  UserOp.sender, during its validateUserOp.  The account can get its own codehash and require that UserOp.signature covers it as well.  If its implementation is not the one intended in the current UserOp, then it fails validation and the bundle would revert if it tries that.  In that case the UserOperationEvent is not emitted and the UserOp stays in the mempool for some honest bundler to include it with the right implementation in the 7702 transaction.



 SamWilsn:

I have to apologize again for not fully understanding all the 4337 specifics.


because I’m only explaining a part of the 7702-4337 integration here.  It’ll become clearer when we publish the whole integration.  We’ll post about it soon.

Author: dror
Date: 2024-05-09T07:06:25.798Z

txgyy:

The risk of permanently upgrading an EOA to a CA is significant (as EOAs carry historical baggage), but addresses generated by algorithms like secp256r1 are not EOAs, so permanently setting code carries no additional risk


The purpose of this EIP was to let existing eoa to run code. Using different signature creates a new address, and enshrine yet another signature into the protocol.
Our goal is to gradually switch over to AA, where the contract controls the signature scheme

Author: dror
Date: 2024-05-09T07:09:41.855Z

SamWilsn:

From a quick estimate, the smallest reasonable proxy is what, like 50 bytes


Putting an address has the benefit of using shorter vanity addresses, say 16 bytes…
The point is that you’re using a code that was deployable on this network (you copy a code that used a constructor)

Author: Amxx
Date: 2024-05-09T11:04:40.332Z

Is this not analogous to handing a signed (but unbroadcast) transaction to someone, and now that someone can also bump your nonce?

A signed (and not broadcasted) transaction must be signed, and can only be used one. In the case of 7702, the EOA doesn’t fully control if the signature is used multiple time. If the code signed includes (for any reason, accidentally or maliciously) a non restricted access to CREATE, then that be leverages for DoS attack on the EOA. Signed (and not broadcasted) transaction doesn’t present the same long-lasting risk

geth (and I assume other clients) protect against similar attacks by limiting the number of pending transactions per account.

I’m not sure how this is relevant. This issue can appen with just one or two pending transactions, which is definitelly within the limit of the clients.

Is using 7702+CREATE /CREATE2 /etc. worse than invalidating pending transactions using a private mempool and a number of normal transactions?

I’m not sure how the client update the mempool when processing new blocks. If it is only considering nonce increase for the origin of each tx in a block … then it would be needed to also observe nonce change that are more “hidden” in the execution trace.
Note that this will also mess up with the wallets that cache the nonce for the signer (I remember having many issues with this a few years ago, no sure if it is still a thing). For sure that is offchain code that can be updated …

Author: SamWilsn
Date: 2024-05-09T14:16:11.426Z

Amxx:

A signed (and not broadcasted) transaction must be signed, and can only be used one. In the case of 7702, the EOA doesn’t fully control if the signature is used multiple time. If the code signed includes (for any reason, accidentally or maliciously) a non restricted access to CREATE, then that be leverages for DoS attack on the EOA. Signed (and not broadcasted) transaction doesn’t present the same long-lasting risk


If the contract_code has even the most basic nonce/replay protection, they are equivalent then? And if we have in-protocol revocation (which I’m not in support of), you can revoke the CREATE-ing code.



 Amxx:

I’m not sure how this is relevant. This issue can appen with just one or two pending transactions, which is definitelly within the limit of the clients.


It’s relevant because clients already have protection against similar attacks, which would also protect against this one.



 Amxx:

I’m not sure how the client update the mempool when processing new blocks. If it is only considering nonce increase for the origin of each tx in a block … then it would be needed to also observe nonce change that are more “hidden” in the execution trace.


They’d just have to expand what’s under consideration to include the signers in these bundles (in addition to tx.origin.)



 Amxx:

Note that this will also mess up with the wallets that cache the nonce for the signer


No worse than using two different wallets with the same seed phrase.

Author: Amxx
Date: 2024-05-09T14:32:16.247Z

SamWilsn:

If the contract_code has even the most basic nonce/replay protection, they are equivalent then? And if we have in-protocol revocation (which I’m not in support of), you can revoke the CREATE-ing code.


I very strongly support in-protocol revocation. I think the protocole should not assume that all contract_code will be be bug free. There will be code that has issue weither that is a malicious action of just by mistake.
If we go with a in-protocole revocation, it is likelly going to be based on some transaction signed by the EOA … which is exactly what the CREATE-ing code can DoS. In the worst case, an attacker would have a user sign a malicious code, and would put an open CREATE in it, so that if the user ever realise it signed something malicious and want to revoke it, the revocation can be front-run in a way that consumes the nonce.

Author: ankurdubey521
Date: 2024-05-09T14:35:06.893Z

yoavw:

It would have to be known to the protocol, and in fact ERC-7562 doesn’t need to know about it. Revocation is a protocol feature, not a 4337-related feature. The protocol needs to stop respecting a signature if it has been revoked, which requires it to know about NonceManager. This does complicate the EIP and I’m still not sure it brings much benefits beyond maxNonce - which keeps things as simple as possible while supporting protocol-level revocation.


Understood, yeah I can’t think of a way to make the nonceManager solution safe to use without enforcing associativity.
My concern with the maxNonce solution is that it introduces a bumpNonce operation specifically for revocations and I’m unsure of how we’ll decide on an appropriate maxNonce, but if that’s significantly less effort than enforcing associativity then perhaps it’s the more practical solution.

Author: benaadams
Date: 2024-05-09T14:35:26.618Z

vbuterin:

Should the contract_code instead be an address? This would save calldata, though only a little bit of calldata because ERC-1167 proxies  only take 44 bytes.


No, because it closes off security avenues.
If the code/initcode is run it can include things like chainId or other parameter constraints (.e.g timestamp expiry) which is then signed and they can be set with TSTORE to form constraints for the outer signer which then pays for and passes data to (proxy) contract.
If its just contract address, then the inner signer cannot sign any additional constraints on the invocation. (While leaving what those additional fields are flexible and up to ERC standardisation)

Author: SamWilsn
Date: 2024-05-09T14:38:00.941Z

I feel like I’m not communicating my concern well enough 
When you transfer an ERC-1155 token, if the recipient account has code, the token contract will call onERC1155Received on the recipient account.
If onERC1155Received reverts or returns the wrong value, the token transfer reverts.
The attack is as follows:

I sign any 7702 operation that doesn’t contain an onERC1155Received implementation.
You try to send me an ERC-1155 token using a 7702 operation.
The bundler includes my operation from (1) followed by your operation from (3) in the 7702 transaction.
Your token transfer reverts because my account has code.

My EOA is not submitting a 4337 UserOp in (3) or (4).

Author: yoavw
Date: 2024-05-09T15:01:32.024Z

SamWilsn:


The bundler includes my operation from (1) followed by your operation from (3) in the 7702 transaction.






 SamWilsn:

My EOA is not submitting a 4337 UserOp in (3) or (4).


The bundler can’t include your operation if it’s not a UserOp.
But I understand your concern, even though not exactly with the flow you described.  You’re right that the bundler could include your previously-signed contract code in the 7702 transaction it is sending, even though it doesn’t include any operation from you.  So if someone else submitted a UserOp that is making an ERC-1155 transfer to your account, a malicious bundler could make the transfer revert.  As a user you have no way to defend yourself against such attacks, other than revoking the signature on that contract you previously signed.
It could be mitigated with some best practices.  For example, wallets should not sign implementations that miss common callbacks such as onERC1155Received.

Author: yoavw
Date: 2024-05-09T15:07:43.394Z

ankurdubey521:

My concern with the maxNonce solution is that it introduces a bumpNonce operation specifically for revocations and I’m unsure of how we’ll decide on an appropriate maxNonce, but if that’s significantly less effort than enforcing associativity then perhaps it’s the more practical solution.


I think choosing a maxNonce is not too tricky.  Any 32 bits number of transactions that you’re unlikely to ever reach will do.  It is probably safe to assume at a user will never send 100 million transactions, and you can still safely bump the nonce by 100 million for revocation without getting anywhere close to the 64 bits nonce limit.
Some confusion around the maxNonce proposal arises from the fact we’re overloading the nonce for something other than replay protection.  Revocation and replay protection are two separate features and ideally we would have used two separate values.  The reason we’re using nonce is because it’s already in the account trie and it’ll be best not to add another value to it.  You can look at it as if we’re using the high bits of the nonce for revocation, and the low bits for replay protection.

Author: kopykat
Date: 2024-05-09T15:12:20.207Z

Similar to the topic of disallowing storage writes in the context of an EOA (which I am in favor of), are there things that could break if EOAs can emit events? In my mind this would only be offchain infrastructure but there could nonetheless be dangerous edgecases, such as wallets thinking a certain signer is installed since an event was emitted but that signer actually not having been set. Arguably, the offchain infra should change but I wanted to flag this anyways.

Author: kopykat
Date: 2024-05-09T15:13:31.438Z

It could be mitigated with some best practices. For example, wallets should not sign implementations that miss common callbacks such as onERC1155Received.

This could nonetheless still be an issue if an account implements logic to block some transfers in certain cases

Author: SamWilsn
Date: 2024-05-09T15:21:40.114Z

yoavw:

The bundler can’t include your operation if it’s not a UserOp.
But I understand your concern, even though not exactly with the flow you described. You’re right that the bundler could include your previously-signed contract code in the 7702 transaction it is sending, even though it doesn’t include any operation from you. So if someone else submitted a UserOp that is making an ERC-1155 transfer to your account, a malicious bundler could make the transfer revert. As a user you have no way to defend yourself against such attacks, other than revoking the signature on that contract you previously signed.


Yes, that’s exactly what I was trying to describe. Included in the 7702 transaction without being in the 4337 bundle.



 yoavw:

It could be mitigated with some best practices. For example, wallets should not sign implementations that miss common callbacks such as onERC1155Received.


You cannot mitigate against callbacks that haven’t been invented yet.
You have to actively revoke, even though you might not know it’s a problem. Even worse with multiple chains.

Author: yoavw
Date: 2024-05-09T15:37:59.073Z

SamWilsn:

You cannot mitigate against callbacks that haven’t been invented yet.
You have to actively revoke, even though you might not know it’s a problem. Even worse with multiple chains.


Right.  You can revoke and sign a new implementation when new ERCs with callbacks become common, but you might not know it.
That’s a caveat when implementing something with replayable signatures.  Do you see a way to mitigate it without adding replay protection?



 kopykat:

This could nonetheless still be an issue if an account implements logic to block some transfers in certain cases


Right, an implementation may intentionally block some callback, although it’s hard for me to find a good example in the 7702 case.  The contract only exists during the transaction.  Suppose you want to prevent ERC-1155 transfers from blacklisted addresses - then you’re only blocking them for the duration of the current transaction but anyone can transfer it to you in a separate transaction.  If your account needs to prevent certain transfers it should have permanent code.

Author: SamWilsn
Date: 2024-05-09T15:42:35.980Z

yoavw:

Do you see a way to mitigate it without adding replay protection?


Yes, use initcode instead of deployed bytecode. The contract can check whatever conditions it wants before choosing to deploy.
4337 bundlers can have a list of known-safe initcodes, do simulations, or some other mechanism I think?

Author: dror
Date: 2024-05-09T15:47:35.239Z

Suggested revocation mechanism:

In EIP-7702 transaction type, add a flag for each account’s tupple e.g (data,r,s,v,bump)
If the flag is set, bump the nonce (e.g. by 2^32) after the execution of this transaction.
This way, this transaction is only one that can use this signature, since the nonce was bumped.
Obviously, it revokes all other signed signatures as well

This model has several benefits:

no extra opcode or transaction type added.
the “bump nonce” operation itself can use gas-abstraction framework.
it is clearly visible in the transaction itself that it is a nonce-changer, so block builder can infer the validity of other transactions used by the same account.

Author: yoavw
Date: 2024-05-09T16:13:04.330Z

SamWilsn:

Yes, use initcode instead of deployed bytecode. The contract can check whatever conditions it wants before choosing to deploy.


What conditions would initcode check in this case to refuse deployment?  It gets called before anything else happens in the transaction so it doesn’t know that it’s going to be used in a bundle that triggers such a transfer.  A concrete example would help here.
And if it could somehow check, it would involve state access and would therefore be unusable in the 4337 context.



 SamWilsn:

4337 bundlers can have a list of known-safe initcodes, do simulations, or some other mechanism I think?


Nothing in 4337 is whitelisted/permissioned and that’s not going to change with 7702.  Bundlers should not whitelist account implementations and exclude others.  Any account that adheres to the ERC-7562 rules should be served.

Author: SamWilsn
Date: 2024-05-09T16:26:35.621Z

yoavw:

What conditions would initcode check in this case to refuse deployment?


I’d go with a nonce.



 yoavw:

And if it could somehow check, it would involve state access and would therefore be unusable in the 4337 context.


That isn’t exactly true, right? If the mempool/bundler knows exactly what conditions can cause the op to become invalid, it can be safely propagated/submitted.
A nonce contract with strict rules about invalidation could serve that purpose.



 yoavw:

Nothing in 4337 is whitelisted/permissioned





 yoavw:

Any account that adheres to the ERC-7562 rules should be served.


The obvious implication is that accounts that do not adhere to 7562 do not need to be served.
That is equivalent to defining your whitelist as “all contracts adhering to 7562”.
I can avoid saying “whitelist” if its implication of human interaction is too strong to ignore.
For initcode to be possible, it is necessary (but not sufficient) to write 7562-like rules for bundlers. So my question becomes:
Is it “possible” or “impossible” to write 7562-like rules for initcode?

Author: dror
Date: 2024-05-09T16:44:24.098Z

SamWilsn:

That is equivalent to defining your whitelist as “all contracts adhering to 7562”.


Not exactly: whitelisting is a manual process to decide that “X” is good or bad, where the code (of block-builder, bundler, or on-chain) can’t verify it, and has to trust that external entity that whitelisted it.
The erc-7562 rules are automatic, and deterministically verify that the validation code is consistent (does the same off-chain and on-chain) and isolated (can’t interfere with validation of another UserOp)



 SamWilsn:

Is it “possible” or “impossible” to write 7562-like rules for initcode?


So yes, it is possible, but I’m not sure what you can check: specifically, you’re limited to storage associated with your own address (account storage is allowed but irrelevant for an EOA, so you’re only allowed to access your own token balances)

Author: SamWilsn
Date: 2024-05-09T16:46:04.406Z

dror:

you’re only allowed to access your own token balances


If that’s already allowed by 7562, represent your nonce as an ERC-20 and burn your nonce by minting yourself a new token

Author: SamWilsn
Date: 2024-05-09T16:48:26.266Z

dror:

whitelisting is a manual process





 SamWilsn:

I can avoid saying “whitelist” if its implication of human interaction is too strong to ignore.


Acknowledged! I will refrain from saying whitelist.

Author: yoavw
Date: 2024-05-09T18:12:25.587Z

SamWilsn:

I’d go with a nonce.


Got it. So you’re not talking about checking conditions specific to the way the contract is used, but add replay protection at the beginning of the transaction rather than when the contract is first called during that transaction.  That makes sense.



 SamWilsn:

That isn’t exactly true, right? If the mempool/bundler knows exactly what conditions can cause the op to become invalid, it can be safely propagated/submitted.


No.  It’s not enough to know what conditions are checked.  You also need to know that they can’t be used to invalidate multiple UserOps with one change.



 SamWilsn:

A nonce contract with strict rules about invalidation could serve that purpose.


Yes.



 SamWilsn:

That is equivalent to defining your whitelist as “all contracts adhering to 7562”.


This is equivalent to saying that Ethereum whitelists only EOAs that use ECDSA signatures and have ETH.  That’s not whitelisting - that’s the protocol.  7562 is the protocol.



 SamWilsn:

Is it “possible” or “impossible” to write 7562-like rules for initcode?


It is possible to write such initcode, just not easy.  And it would require bundlers to work harder during propagation and simulate 7702 transactions rather than just 4337 validations.
But given the use case you highlighted, it might make sense to do that.  4337 accounts would have to use a pure initcode, whereas other contracts can do different things in initcode.



 dror:

So yes, it is possible, but I’m not sure what you can check: specifically, you’re limited to storage associated with your own address (account storage is allowed but irrelevant for an EOA, so you’re only allowed to access your own token balances)



I think @SamWilsn is talking about a contract that is not meant to be used in a UserOp, so it’s ok for its initcode to do anything.  Only contracts used in UserOps need to follow these rules.  If a node propagates a UserOp with a non-compliant initcode it’ll simply get banned by other nodes for spamming invalid ops.
In UserOps, initcode wouldn’t be allowed to use associated storage, for the same reason a deployment UserOp can’t use associated storage unless the factory is staked.  In the 7702 case this means no storage access in initcode whatsoever because there’s no EOA storage and associated storage cannot be allowed.




 SamWilsn:

If that’s already allowed by 7562, represent your nonce as an ERC-20 and burn your nonce by minting yourself a new token 


No.  See my reply to Dror above.  Tokens require the associated storage rule, which does not apply during deployment unless it is done by a staked factory (which is not the case here).
But I think it doesn’t matter for your use case.  You are talking about checking a nonce in initcode of a contract not meant to be used with 4337, so the 4337 rules are irrelevant.  The initcode can do whatever it wants, it just won’t be usable in a 4337 bundle.
To summarize, I do see your point for using initcode in non-4337 use cases.  If we can’t find another way to solve the same use case, then you convinced me that initcode is needed.  Bundlers will have to inspect initcode in UserOps that specify a 7702 contract to ensure that it is pure.  4337 accounts should simply have an empty constructor and do everything in validateUserOp instead.

Author: derek
Date: 2024-05-09T19:21:51.773Z

With the maxNonce + bumpNonce proposal, would there be the concern that a user can be tricked into bumping their nonce to the max value 2^64-1 and therefore effectively bricking their account?

Author: wjmelements
Date: 2024-05-09T20:15:48.244Z

https://github.com/ethereum/EIPs/pull/8545

Author: matt
Date: 2024-05-09T21:31:23.317Z

Amxx:

I very strongly support in-protocol revocation. I think the protocole should not assume that all contract_code will be be bug free. There will be code that has issue weither that is a malicious action of just by mistake.


Nowhere else in the protocol do we carve out fallback mechanisms for buggy code. The protocol doesn’t force smart contract wallets to have a revocation. Let’s not make the mistake for transient smart contract wallets.

Author: yoavw
Date: 2024-05-09T21:38:16.966Z

No, since bumpNonce takes a uint32 and the nonce is uint64.  The user would have to be tricked to bumping it 4 billion times to cause that.  That’s a lot of signing to do.

Author: matt
Date: 2024-05-09T22:39:45.528Z

dror:

Instead of providing the code in each transaction, we could instead provide an address, and CODECOPY the code from there.
Its true that small static proxies are only 44 bytes - but what if we want to use another proxy? adding yet another small static proxy just to reduce the TX size seems a bad solution.


I agree with this, we should specify the code with their 20 byte identifier (address).



 yoavw:

I understand what you mean. This could happen. But the issue is that EOA A signed something it shouldn’t have - a replayable that sets a bad implementation (with no receive()). If it took care to only sign implementations that follow the best practices (which we still need to write), it should be safe.


They should also take care to only sign implementation that follow the best practices for revocation. 



 ducthotran2010:

I’m curious why we do not include a specific amount field in this proposal, considering it permits interactions with any destination accounts but doesn’t directly allow transferring native tokens when initiating the transaction.


I think the originating transaction should be able to send value.

Author: yoavw
Date: 2024-05-09T22:50:12.860Z

matt:

They should also take care to only sign implementation that follow the best practices for revocation. 




Not the same. The user has a way to recover from signing a contract that didn’t follow best practices, by revoking it.  But no way to recover from signing a contract that doesn’t implement revocation if the protocol doesn’t provide a way.  Revocation is the user’s last line of defense.


See later messages - Sam already convinced me that it’s not good enough and we need initcode to enable mitigation.  It’ll complicate things a bit for 4337 but I see no way to mitigate it otherwise.

Author: matt
Date: 2024-05-09T22:52:42.621Z

yoavw:

The user has a way to recover from signing a contract that didn’t follow best practices, by revoking it. But no way to recover from signing a contract that doesn’t implement revocation if the protocol doesn’t provide a way. Revocation is the user’s last line of defense.


Why don’t you have in-4337 revocation for users if you feel so strongly about it?

Author: yoavw
Date: 2024-05-09T23:23:44.176Z

matt:

Why don’t you have in-4337 revocation for users if you feel so strongly about it?


How would that work?  The validation function is a part of the account, not a part of the protocol.  The user has no way to prove identity to EntryPoint.  But EOAs do have protocol level identity proving because the account is not abstracted.  The 7702 contract does not become the account.  It is only authorized to act inside the account.  Therefore revocation makes sense.  If the contract became the account (as in 5003 or 7377) then there couldn’t be a revocation mechanism because the protocol can no longer identify the user.

Author: matt
Date: 2024-05-10T00:01:44.333Z

4337 would certainly need to restrict accounts a bit.
It could enforce all compatible accounts have code that is exactly a proxy contract where only the entry point can set the implementation. Every 4337 account code will be the same ~50-100 byes and they can point to whatever implementation code they like.
In the entry point (the 4337 protocol), there would need to be a new mechanism to authenticate implementation change requests. Since there is “no way to recover from signing a contract that doesn’t implement revocation”, we can’t trust user code. There will need to be a list of allowed authorization modules which the protocol assumes is safe. In the event this is enshrined, these modules will simply become native code. Generally as long we support multi-sigs from a wide range of crypto primitives, that is probably a reasonable place to start. Open to other module types, but it’s possible to add more later as-needed. Once the entry point authenticates an implementation change request, it can dispatch it to the user’s smart account.
Is this as powerful as 4337 is today? No. Is it safer? By your argument “revocation is the user’s last line of defense” and the desire to enshrine a revocation scheme in the core protocol: yes.
Now of course I don’t support this type of mechanism. I think users and wallets have the responsibility to do things that are safe. However, I don’t see why if revocation is that critical that we can’t write it into 4337 or some native account abstraction proposal. It will never be as powerful as just letting the user run whatever code they want, but if we have the opinion that the protocol needs to protect users then let’s protect all the users.
–



 yoavw:

The 7702 contract does not become the account. It is only authorized to act inside the account.


There is no difference between the two. In both cases a user has authorized code to act inside the account. What code is running is simply an implementation detail.

Author: yoavw
Date: 2024-05-10T00:36:43.384Z

Trolling aside, why do you oppose to a revocation mechanism like maxNonce?  Can you point out a use case it blocks?  Or maybe a way in which it restricts the user?  Or some UX degradation?  A cost increase?  You seem to feel so strongly about it, so there must be some reason I’m missing.
It’s merely an emergency mechanism that comes at no cost and can save the user from disasters.  Set maxNonce to 2^32-1 and it only invalidates the sig if the user makes more than 4 Billion transactions.  Do you see that happening?
As long as the user sends less than 4 billion transactions, there is no observable effect to this mechanism, nothing the user needs to do or know, no additional flows to implement in the wallet or in any dapp, no additional state for nodes to store.  The only flow associated with it, is bumping the nonce in case of emergency (that for most users would hopefully never happen).
If revocation deteriorated some use case, e.g. if we just used the nonce as-is so that sigs would keep becoming invalid when the user transacts, then we would need to debate whether it is worth it.  But if there’s no observable cost to the user and everything works the same way, why are we debating this?
What’s the downside, other than me proposing it?



 matt:

There is no difference between the two. In both cases a user has authorized code to act inside the account. What code is running is simply an implementation detail.


It’s the difference between authorizing someone to make recurring withdrawals from your bank account, and letting someone be your bank.

Author: matt
Date: 2024-05-10T01:20:38.355Z

yoavw:

Trolling aside


It isn’t a troll. You are on one hand advocating for in-protocol revocation with 7702 because it is “the user’s last line of defense”, yet in 4337 provide no such defense for users. That isn’t consistent.
Maybe what I proposed as a revocation system for 4337 isn’t great, but if we worked on it a bit it would probably end up in a decent state. It would restrict 4337 accounts, yes. But so does max nonce.
I will admit that the max nonce does not restrict EOA accounts much, especially if it’s possible to sign arbitrarily large nonces. But it is still an unnecessary wart in the protocol – as seen by 4337s lack of revocation.



 yoavw:

If there’s no observable cost to the user and everything works the same way, why are we debating this?
What’s the downside, other than me proposing it?


It has nothing to do with the proposer  . My order of preference is:

no revocation
max nonce
current nonce

If we must have in-protocol revocation, maxNonce is my preference because I believe it is a better mechanism than the current nonce mechanism.
In the max nonce proposal you suggested I can’t see an observable cost to the user beyond the additional 8 bytes of tx data to include the nonce in the code / sig tuple. At this point, the cost is to the protocol in additional and unnecessary complexity.
I will add that it isn’t perfectly clear how to deal with invalid nonces in 7702 though. We don’t want that to cause the entire bundle to become invalid and dropped, but it also feels a little weird to allow invalid ones in the tx. It seems like the latter is most similar to how it would have behaved in 3074 so I suppose we can go with that until a better solution is discovered.

Author: SamWilsn
Date: 2024-05-10T01:59:50.697Z

Did some back of the napkin estimation for how much code would be required per signature.
Looks like it’ll be about 78 bytes, and you get:

chain id check
revocation logic
bytecode copied from an on-chain template contract

Here’s the (untested) bytecode I used: contract_code.etk · GitHub

Author: dror
Date: 2024-05-10T06:17:59.658Z

First, let’s move 4337 (or any SCA, like Safe) revocation to its own thread. If you can suggest a general to force ability of future “update impl”, while keeping it decentralized ,I’m all for it.
The user doesn’t opt-in to use 7702 accounts .
once the protocol is added, the wallet, not the user, decides when to sign something.
Since there is a “one source of truth” (ecdsa sig), I think it should be used to limit “eternal damage”.
And re: nonce bump

It doesn’t increase the tx size, just like tx nonce doesn’t appear in a normal tx. You only sign it.
There is one observable side effect to the current suggested 2^32 bump: off-chain code treat nonce as total txs of the account (well, that’s the rpc name eth_getTransactionCount)
The protocol currently limits nonce to 64 bit, but afaik, the code uses a whole storage slot.
What if the bump is increased to 2^64? that side-effect is removed (but requires a separate rpc to read it)

Author: etan-status
Date: 2024-05-10T06:52:08.721Z

Adding a side note that this would be easily integratable into EIP-6493 SSZ Transaction as well. RLP transaction types are quite difficult to deprecate over time (it only ever partially happened for the replayable transactions without chain ID, which are refused at RPC level but still accepted in blocks)

Author: derek
Date: 2024-05-11T03:14:21.250Z

@yoavw not sure if you already described it somewhere but how exactly would bumpNonce be implemented?  A new opcode?  Something in this new transaction type?
Also, @SamWilsn seemed to have convinced you that we need initcode but I’m having trouble pinpointing exactly what he said that convinced you.  Do either of you mind explaining?

Author: SamWilsn
Date: 2024-05-11T03:33:44.505Z

derek:

Also, @SamWilsn seemed to have convinced you that we need initcode but I’m having trouble pinpointing exactly what he said that convinced you. Do either of you mind explaining?


If the bytecode contained in a 7702 operation is deployed unconditionally, then any old signature can be re-included in a later 7702 transaction to have the bytecode deployed. This causes problems for ERC-1155 token (and similar) transfers because the bytecode might not implement onERC1155Received.

Author: derek
Date: 2024-05-11T03:41:28.814Z

Ah so you are proposing that we include initcode but not do any of the revocation proposals such as maxNonce right? Since any of the revocation proposals would address this issue.
I was confused since @yoavw seemed to want to include both maxNonce and initcode, but maybe I misunderstood.

Author: matt
Date: 2024-05-11T19:12:42.248Z

dror:

And re: nonce bump […] it doesn’t increase the tx size, just like tx nonce doesn’t appear in a normal tx. You only sign it.


This is incorrect. The nonce is in the sig hash. You can’t compute the sender unless you know the nonce. Therefore to implement the max nonce scheme, you will marginally increase tx size.



 dror:

There is one observable side effect to the current suggested 2^32 bump: off-chain code treat nonce as total txs of the account (well, that’s the rpc name eth_getTransactionCount)
The protocol currently limits nonce to 64 bit, but afaik, the code uses a whole storage slot.
What if the bump is increased to 2^64? that side-effect is removed (but requires a separate rpc to read it)


Yes this is true. I don’t know how people are using this invariant, but I feel a bit hesitant to allow bumping where the cost to bump doesn’t increase linearly with size of the bump.
Besides that, we limited the nonce size in EIP-2681 and I don’t think we should remove it. Many clients are written with this assumption by using uint64 to store nonce values.

Author: yoavw
Date: 2024-05-11T20:36:33.770Z

matt:

It isn’t a troll. You are on one hand advocating for in-protocol revocation with 7702 because it is “the user’s last line of defense”, yet in 4337 provide no such defense for users. That isn’t consistent.


If it isn’t then I’ll answer seriously.  I think you’re proposing for accounts to have two identity systems, so that each account will effectively be a 1-of-2 multisig.  The user has to maintain keys for both, and a compromise of one can compromise the account.  That seems to degrade security rather than improving it, which I don’t think can be said for maxNonce in 7702.
If you want to propose an improvement for 4337, preferably one that doesn’t break the existing 4.3M deployed accounts (any more than maxNonce breaks existing EOAs), please do it in the 4337 thread or a separate one and we can discuss it there.  No point in hijacking the 7702 thread for 4337 discussions, as people already complain that it’s hard to follow the current thread.



 matt:

I will admit that the max nonce does not restrict EOA accounts much, especially if it’s possible to sign arbitrarily large nonces. But it is still an unnecessary wart in the protocol – as seen by 4337s lack of revocation.


Adding a security feature at zero cost is different from adding it at the cost of degrading functionality/security.  I don’t see use cases that become impossible or even different with maxNonce, and it doesn’t degrade account security, but strictly improves it.
Anyway, I shouldn’t be the only one arguing for it.  Let’s wait for all core devs and for the community to bring their perspective.  This issue does not interact with the AA roadmap and if everyone is ok with not having protocol level revocation, I’m not going to be the only one to insist.



 matt:

In the max nonce proposal you suggested I can’t see an observable cost to the user beyond the additional 8 bytes of tx data to include the nonce in the code / sig tuple. At this point, the cost is to the protocol in additional and unnecessary complexity.


I think we agrees on the pros and the cons of maxNonce vs. not having protocol level revocation, just not on what the right trade off is.  At this point we should let the community decide on the right trade off.



 matt:

I will add that it isn’t perfectly clear how to deal with invalid nonces in 7702 though. We don’t want that to cause the entire bundle to become invalid and dropped, but it also feels a little weird to allow invalid ones in the tx. It seems like the latter is most similar to how it would have behaved in 3074 so I suppose we can go with that until a better solution is discovered.


That’s a good question.  From 4337 perspective they’re equivalent - the bundle will revert whether it happens at the transaction level or inside EntryPoint when it fails to call the account’s validateUserOp.  So DoS resistance depends on revocation being expensive.  For non-4337 use cases it might matter, so let’s wait for feedback from some.  Going with the latter seems fine as a default.



 matt:

I feel a bit hesitant to allow bumping where the cost to bump doesn’t increase linearly with size of the bump.


I also think it should be an expensive operation but I’m curious why you think it should increase linearly rather than a fixed cost that is significantly higher than the cost of invalidating 63 pending transactions (or a 4337 bundle for that matter).  Can it cause more work than invalidating the max number of pending transactions per EOA?

Author: yoavw
Date: 2024-05-11T20:48:13.465Z

No, initcode based revocation and maxNonce serve different purposes and I’m not suggesting that one should remove the other.  The former is a way for the contract to implement arbitrary revocation logic, which can mitigate the attacks that @SamWilsn and @taek.eth suggested.  The latter is a way for the user to revoke access unilaterally even if the contract turned out to be buggy or malicious.
In my opinion both as valuable independently, but @matt would argue that implementing revocation in the contract itself is sufficient.  At this point it would be valuable to get feedback on this from you and other community members on whether we need both.

Author: frangio
Date: 2024-05-12T01:03:53.267Z

yoavw:

The latter is a way for the user to revoke access unilaterally even if the contract turned out to be buggy or malicious.


Revocation logic is extremely simple. Are we really this pessimistic about our ability to implement it correctly? This community has done harder things.
We should be able to implement a simple revocation contract and include a call to check revocation status as a prelude in EIP-7702 signed code, in a standard way that is easily statically checkable.

It would be good to hear if there is consensus about switching to initcode. It seems necessary to protect against attacks like the one on ERC-1155 transfers.

Author: dror
Date: 2024-05-12T09:40:16.327Z

matt:

The nonce is in the sig hash . You can’t compute the sender unless you know the nonce.


Yes, technically, I suggested to introduce a separate “revocation nonce” managed by each account.
Since EIP-2681  limited the nonce to 64-bit, it made the upper 192 bits “reserved” and currently must be zero.
My suggestion is to reuse these as “revocation nonce”, used only by 7702 signature.
It does require a separate “bump revocation nonce” mechanism.
The one scenario this model can’t handle (and “maxNonce” can) is “maxNonce = nonce+1” - that is, a signature that is valid for exactly one transaction: This is a scenario where the user signs each transaction twice (once as account signer, once as transaction signer (and payer)), but is guaranteed the signature can’t be replayed (this mode also prevents using gas abstraction)

Author: yoavw
Date: 2024-05-12T09:44:30.808Z

frangio:

Revocation logic is extremely simple. Are we really this pessimistic about our ability to implement it correctly? This community has done harder things.


I’m not pessimistic about our ability to implement it correctly, but I’m very pessimistic about everyone implementing it correctly (or using the same implementation).  As a security researchers I’ve seen some really bad contracts on mainnet.  Doing it at the protocol level ensures that users will be able to revoke buggy implementations.  I wouldn’t suggest it if it broke important use cases but it seems not to break any.
The case I have in mind is when you start with a wallet that wasn’t as diligent as you’d like when writing its contract.  When you accumulated assets and became more savvy, you realized it and decided to switch to a better wallet.  But if the old one didn’t implement its own revocation (whether for lack of knowledge or in order to be “sticky”), you’re stuck with your old wallet forever.
On the other hand, as Matt pointed out, the same is true if you select a bad contract wallet, so the difference is that with 7702 it is possible to have a recovery mechanism “for free” whereas with a contract wallet it’s not.
Maybe the community decides that it’s not needed and everyone will use good implementations. If everyone is ok with that, I’m not going to be the only one to insist otherwise.



 frangio:

It would be good to hear if there is consensus about switching to initcode. It seems necessary to protect against attacks like the one on ERC-1155 transfers.


I don’t know.  Maybe @SamWilsn can comment on where we stand with initcode.

Author: dror
Date: 2024-05-12T09:51:49.313Z

frangio:

Revocation logic is extremely simple. Are we really this pessimistic about our ability to implement it correctly? This community has done harder things.


Yes, any 7702 contract can implement revocation very simply. That’s true. The problem is when a user signs such a contract that doesn’t implement a revocation mechanism: In that case, that contract is authorized to be used on this account forever, without being able to revoke.
e.g: assume a cool 7702-contract that supports some specific feature, but has a buggy revocation.
Now there is a signature “out there” that can prevent you from receiving tokens, if you use decentralized relayer (e.g 4337): Any time you submit a transaction, they will front-run it, and re-relay it - with the above signed code, which will cause the TX to run but revert on the token callback.
Yes, you could use private mempool/relayer, or send a direct TX (and paying with ETH) - but this break the UX for many users, who are not sophisticated enough.

Author: daniellehrner
Date: 2024-05-12T13:42:50.824Z

I am against any operation like bumpNonce or similar. The yellow paper defines nonce as equal to the transaction count. Arbitrary jumps of the nonce would break this definition. Further would it break eth_getTransactionCount as this also just return the nonce, we have no other way of tracking the number of transactions currently. eth_getTransactionCount is used by many (all?) libraries and wallets to get the next nonce when creating a transaction. We would need another RPC endpoint (eth_getNonce ?)  and all libraries and wallets would need to switch to that. That is a huge hassle and would surely break many apps.
All this can be avoided by using the same mechanism as 3074: signing with the current nonce and revoking by increasing it by 1. This keeps all the current definitions and behavior.

Author: frangio
Date: 2024-05-12T17:08:50.249Z

yoavw:

But if the old one didn’t implement its own revocation (whether for lack of knowledge or in order to be “sticky”), you’re stuck with your old wallet forever.
On the other hand, as Matt pointed out, the same is true if you select a bad contract wallet


It’s not true for either case. You can always transfer your assets over to a new wallet. I think you’re aware of this but it’s worth making explicit for others.
It’s also worth repeating that this problem is not exclusive to EIP-7702 or EIP-3074. The same can happen if you choose a wallet and later realize it used bad randomness or that the private key was leaked.
We mitigate the risk for private keys by building excellent libraries that implement the tricky parts, and complement it with a culture of caution and skepticism. We can always improve on both fronts but they’re concerns of the application and social layers, not the protocol layer.

Author: yoavw
Date: 2024-05-12T18:02:54.366Z

daniellehrner:

The yellow paper defines nonce as equal to the transaction count.


Would this be the first and only time an EIP breaks something in the yellow paper?  Ethereum evolved a lot since.



 daniellehrner:

Further would it break eth_getTransactionCount as this also just return the nonce, we have no other way of tracking the number of transactions currently.


Easily fixable by masking the nonce in eth_getTransactionCount and making bumpNonce only increment the high bits.  I.e. if we use 32 bits then the transaction count remains accurate for the first 4 billion transactions.



 daniellehrner:

All this can be avoided by using the same mechanism as 3074: signing with the current nonce and revoking by increasing it by 1. This keeps all the current definitions and behavior.


I think this would break a lot of use cases and invalidate signatures needlessly, whereas maxNonce doesn’t.
But again - this is just one possible implementation.  Maybe there are better ones, or maybe the community decides it doesn’t need any.  You’re welcome to propose others and we can compare them (or make a case for why we don’t need one).



 frangio:

It’s not true for either case. You can always transfer your assets over to a new wallet. I think you’re aware of this but it’s worth making explicit for others.


I disagree on this one.  Not everything is transferable and it’s indeed worth making it explicit for others.  A couple of examples:

Soulbound tokens
Airdrops eligibility - if someone has control of your account, they can snatch your future airdrops.
Vesting contracts - the tokens are locked, the attacker grabs them as soon as they vest.
Validator withdrawal address - you can’t change it without exiting the validator and withdrawing your 32 ETH, at which point it gets snatched before you restake it.  If you don’t exit, your rewards get snatched regularly so you’re operating your validator for someone else’s benefit.
Governance delegation - you’re a delegate at the governance of a popular protocol, with thousands of users delegating to you.  Now you need to ask them to immediately redelegate to a different address.  Good luck getting all of them to act in a timely manner.

Do you disagree that these cases are effectively non-transferable or that they represent valuable assets?



 frangio:

It’s also worth repeating that this problem is not exclusive to EIP-7702 or EIP-3074. The same can happen if you choose a wallet and later realize it used bad randomness or that the private key was leaked.


Yes, I agree and I quoted Matt on this earlier.  The difference is that here we can protect the use cases above “for free”, whereas with an EOA with bad randomless or with a not-so-smart smart account it isn’t the case.  Should we not protect users when we can (at no cost) because there are other cases where we can’t?



 frangio:

We can always improve on both fronts but they’re concerns of the application and social layers, not the protocol layer.


Unrelated to 7702, but the lines actually get blurry in some cases.  Consider validators withdrawal address for example.  Suppose a liquid staking protocol holds 35% of the staking power and its withdrawal contract is compromised.  The attacker can extort them to support a certain protocolchange.  Is it an application/social layer or could it affect the consensus layer?  But hopefully no one will use a 7702 contract for that, so we can debate this philosophical question elsewhere.

Author: frangio
Date: 2024-05-12T20:19:51.743Z

yoavw:

Do you disagree that these cases are effectively non-transferable or that they represent valuable assets?


No, I agree with that, though I think we should ask if these are good application-layer design decisions, or good user choices! For example, for soulbound tokens Vitalik has discussed the problems with non-transferability, and suggested binding them to ENS names rather than addresses.



 yoavw:

Should we not protect users when we can (at no cost) because there are other cases where we can’t?


If we had a way to add native revocability for free I’d be supportive of it, but all the solutions seem to have some cost, either in complexity to the protocol or in killing use cases people are interested in.
From an app layer perspective I’m not against maxNonce, but protocolwise I hear concerns about it.

Author: yoavw
Date: 2024-05-12T20:48:21.202Z

frangio:

No, I agree with that, though I think we should ask if these are good application-layer design decisions, or good user choices! For example, for soulbound tokens Vitalik has discussed the problems with non-transferability, and suggested binding them to ENS names rather than addresses.


Soulbound tokens - right, better bind them to ENS.  But I’m not sure how the user could be making better choices in most of the other cases.  There’s no way to change validator withdrawal address, change ownership of a vesting contract, change airdrop eligibility address (except rare cases), etc.
One could argue that some of these things should be bound to ENS but in practice they’re not and they’re outside the user’s control.



 frangio:

If we had a way to add native revocability for free I’d be supportive of it, but all the solutions seem to have some cost, either in complexity to the protocol or in killing use cases people are interested in.


The trade offs around maxNonce have been discussed above.  I think it’s practically free and doesn’t break any use case.  But I acknowledge that it’s an additional thing the protocol needs to implement.  These pros and cons should be weighed by the community against protecting use cases such as the above.

Author: daniellehrner
Date: 2024-05-13T08:28:24.424Z

yoavw:

Would this be the first and only time an EIP breaks something in the yellow paper? Ethereum evolved a lot since.


Would it be the first time something has changed, no. Would it be the first time we redefine basic terminology, I think so. At least I can’t think of any other example.



 yoavw:

Easily fixable by masking the nonce in eth_getTransactionCount and making bumpNonce only increment the high bits. I.e. if we use 32 bits then the transaction count remains accurate for the first 4 billion transactions.


Changing RPC responses would be a first AFAIK. At least we have no concept of them changing with hardforks. We can’t know how every library is parsing the JSON hex strings so this still could lead to bugs and unintended side effects. Changing RPC responses is too dangerous in my opinion.



 yoavw:

I think this would break a lot of use cases and invalidate signatures needlessly, whereas maxNonce doesn’t.


I understand and this unfortunate, but as I understand the motivation section of the EIP the goal is to add short-term functionality improvements to EOA. This is still given. If the trade-off is between more functionality and being more secure because of a simple in protocol revocation I opt for the latter. In-protocol revocation was a must for 3047 for many client teams, I think this has not changed, but I might be wrong here.



 yoavw:

But again - this is just one possible implementation. Maybe there are better ones, or maybe the community decides it doesn’t need any. You’re welcome to propose others and we can compare them (or make a case for why we don’t need one).


We had this discussion for 4 years for 3047. Given the tight timeline I have my doubts that we will come up with something better considering that the first devnet is already spinning up this week. I rather have 7702 with limited, but still sufficient functionality than having nothing. A lot of this discussion here seems to be focused on adding features which is not the scope of the EIP IMO. I prefer to keep it simple and make sure to ship it in the next hardfork.

Author: yoavw
Date: 2024-05-13T13:16:46.629Z

daniellehrner:

Would it be the first time something has changed, no. Would it be the first time we redefine basic terminology, I think so. At least I can’t think of any other example.


Looking through the commit history of the yellow paper (yes, it’s a live document and is getting updated frequently), I can dig a few.  For example we removed the term “mining” changed changed the way block production works, and we changed the definition of gas with EIP-1559 and introduced priority fee.  I’m not sure what term we are changing by allowing nonce to be bumped but it seems like a smaller change than some others.



 daniellehrner:

Changing RPC responses would be a first AFAIK. At least we have no concept of them changing with hardforks. We can’t know how every library is parsing the JSON hex strings so this still could lead to bugs and unintended side effects. Changing RPC responses is too dangerous in my opinion.


I didn’t say the returned JSON would be changed.  The implementation could change to mask the high bits out in the node itself.  The change is not observable by users, except those who sent more than 4 billion transactions from their EOA.  Do you think there is one?



 daniellehrner:

If the trade-off is between more functionality and being more secure because of a simple in protocol revocation I opt for the latter.


If being the operative word.  I think we’ve established that it doesn’t disable any functionality.



 daniellehrner:

In-protocol revocation was a must for 3047 for many client teams, I think this has not changed, but I might be wrong here.


I don’t think it has changed and I don’t see why it would.  Hence I proposed a mechanism that satisfies that requirement without breaking any use case.  But if they did change their minds and it’s not needed, that’s fine too.



 daniellehrner:

Given the tight timeline I have my doubts that we will come up with something better considering that the first devnet is already spinning up this week.


The first devnet won’t include any version of 7702 so we have time to come up with better options.



 daniellehrner:

I rather have 7702 with limited, but still sufficient functionality than having nothing.


I agree, I just don’t see the limit on functionality.

Author: Amxx
Date: 2024-05-13T16:18:44.487Z

matt:

The protocol doesn’t force smart contract wallets to have a revocation


The protocol also don’t allow a single address to have constantly changing code that may be approved my multiple wallets.
If you want to talk smart contract wallets, they often include a modular (safe) or upgradeable (argent) design. Unlike a non revocable 7702, a buggy module can be removed. With a non revocable 7702, a buggy module can last forever, and stay unnoticed (unused) for years before it’s exploited. It like not being able to upgrade your install of metamask after a bug is discovered.
7702 is enabling new workflows, far from anything that exists today (and that is what we want). Assuming the the existing security models cover these new workflows is absurde if you ask me. We have to ask ourself what new attack vectors may result from this new transaction type … and eventually include safety measures that did not exist in the past.

Author: matt
Date: 2024-05-13T18:46:00.556Z

Amxx:

If you want to talk smart contract wallets, they often include a modular (safe) or upgradeable (argent) design. Unlike a non revocable 7702, a buggy module can be removed. With a non revocable 7702, a buggy module can last forever, and stay unnoticed (unused) for years before it’s exploited. It like not being able to upgrade your install of metamask after a bug is discovered.


Code executing in your account with sudo permission is not the same as a plugin, so this comparison is moot. A better question is how can you revoke a smart account if the plugin system itself has a bug? The accepted answer is you should have deployed a proxy to your account and must now change the target. If you deploy smart account code into your account (e.g. run it with sudo permission) and it has a bug, there is no mechanism to revoke the code. We accept this as safe in that context, I don’t see a reason to not accept it for EOAs.
Yes 7702 introduces the ability to run different codes in your account. I think that’s okay and maybe their will be some interesting use cases from it. The best way to use it will still be to sign one 7702 message forever which delegates to a proxy contract that executes on your behalf. Then you can change the target at will. Revocation ends up looking the same as smart accounts today: just change the target.

Author: chfast
Date: 2024-05-14T07:03:56.715Z

For reference, the EIP-7702 is very similar to EIP-2803: Rich Transactions.

Author: pdobacz
Date: 2024-05-14T07:30:33.950Z

Just flagging early that EIP-7702 could pose an interesting alternative to the EOF creation transactions EIP-7698, as well as the previous designs with TXCREATE and new InitcodeTransaction type. It seems however to require the “sign over contract_code” version to function as such.

Author: daniellehrner
Date: 2024-05-15T09:35:32.658Z

@yoavw One question: would something like bumpNonce be required / useful in a full AA world? I am asking because one goal of 7702 is to avoid OP codes that aren’t useful anymore once we go full AA.
If it is indeed useful it makes more sense to me to introduce something like this now.

Author: yoavw
Date: 2024-05-15T11:41:46.445Z

daniellehrner:

I am asking because one goal of 7702 is to avoid OP codes that aren’t useful anymore once we go full AA.


Not an opcode.  A transaction type.  Invalidates all past implementations and optionally sets a new one.

Author: daniellehrner
Date: 2024-05-15T12:04:01.115Z

yoavw:

Not an opcode. A transaction type. Invalidates all past implementations and optionally sets a new one.


Thank you for the clarification!
I was about to propose an alternative approach, but as the latest version of EIP states that no in-protocol revocation will be done, that seems unnecessary now:


github.com


ethereum/EIPs/blob/c37305938a3619e00c3ac4d3abe103f8330b6138/EIPS/eip-7702.md
---
eip: 7702
title: Set EOA account code for one transaction
description: Add a new tx type that sets the code for an EOA during one transaction execution
author: Vitalik Buterin (@vbuterin), Sam Wilson (@SamWilsn), Ansgar Dietrichs (@adietrichs), Matt Garnett (@lightclient)
discussions-to: https://ethereum-magicians.org/t/eip-set-eoa-account-code-for-one-transaction/19923
status: Draft
type: Standards Track
category: Core
created: 2024-05-07
requires: 2718, 2929, 2930
---

## Abstract

Add a new transaction type that adds a list of `[address, y_parity, r, s]` authorization tuples, and converts the signing accounts (not necessarily the same as the `tx.origin`) into smart contract wallets for the duration of that transaction.

## Motivation

There is a lot of interest in adding short-term functionality improvements to EOAs, increasing the usability of applications and in some cases allowing improved security. Three particular applications include:




  This file has been truncated. show original

Author: yoavw
Date: 2024-05-15T13:36:47.306Z

daniellehrner:

as the latest version of EIP states that no in-protocol revocation will be done, that seems unnecessary now


Yes, from user security perspective the newly proposed version of this EIP is worse than the current 3074 and is nearly identical to the 2021 version of 3074 (except being a transaction type).  I supported the original version of 7702.  I no longer support the new one, for reasons well beyond revocation.  It doesn’t conflict with the AA roadmap but from most other perspectives it’s worse than the current 3074.

Author: daniellehrner
Date: 2024-05-15T14:02:47.882Z

I was thinking a bit over the latest version and I really do not agree with the design choices. Additionally to what was said above regarding security, allowing SSTORE does conflict with the AA endgame IMO. Once we allow EOAs to migrate to smart wallets, the storage of the EOA might be littered with random data. All the smart wallets must basically clear any storage slot that they want to access to make sure that no left over data is in there.
Further SSTORE can lead to hard to debug issues in the mean time because any smart contract that is executed with 7702 might find itself in the same situation as described before.

Author: yoavw
Date: 2024-05-15T14:59:55.634Z

daniellehrner:

allowing SSTORE does conflict with the AA endgame IMO


Yes, that was one of my points when reading this version.  It precludes migrating the account to a smart contract in the future, unless the user traces all past transactions and sends a transaction to reset every slot not associated with the selected implementation.



 daniellehrner:

All the smart wallets must basically clear any storage slot that they want to access to make sure that no left over data is in there


They can’t do this on-chain.  E.g. if you migrate the account to Safe, there may be garbage in high slots that happen to be mapped to signers in the Safe data structure.  There’s no way to detect that, other then tracing all past 7702 transactions that touched this account.
I started commenting on the PR with this and many other points, but discarded it.  There is just too much.  It’s basically replaying every discussion we’ve had about 3074 since June 2021.

Author: matt
Date: 2024-05-15T15:46:38.364Z

yoavw:

I supported the original version of 7702. I no longer support the new one





 yoavw:




 daniellehrner:

allowing SSTORE does conflict with the AA endgame IMO


Yes, that was one of my points when reading this version. It precludes migrating the account to a smart contract in the future, unless the user traces all past transactions and sends a transaction to reset every slot not associated with the selected implementation.


The “new” version only changes the behavior regarding code deployment. Instead of setting the account’s code to be contract_code, it retrieves the code from address and sets that code as the account’s code.
There is no in-protocol revocation and all opcodes are allowed in both versions.

Author: yoavw
Date: 2024-05-15T16:23:18.766Z

matt:

The “new” version only changes the behavior regarding code deployment. Instead of setting the account’s code to be contract_code, it retrieves the code from address and sets that code as the account’s code.


This ignores the entire discussion above, regarding the conditions in which it is safe to use an address rather than contract_code.
TL;DR signing address instead of code is good for cost-saving (writing 20 bytes instead of the entire code) but the signature should be over the deployed code as well.  Otherwise the trust assumption is exactly like a 3074 invoker, in which case we need chainid in the signature because there is no guarantee that the same code will be deployed on future chains, rather than something different in the same address.
I haven’t seen a good reason not to sign over the code that is deployed in that address.  The transaction propagation rationale is incorrect.  No reason to check signature validity as a condition for propagation, since the sender pays for the gas regardless, even if the transaction reverts.  It’s the sender’s responsibility to check for signature correctness.  An incorrect 7702 signature is equivalent to a good signature on an empty contract - which propagation also doesn’t take into account.  In both cases the transaction reverts at the sender’s expense.



 matt:

There is no in-protocol revocation and all opcodes are allowed in both versions.


…ignoring everything that was discussed in this 126-messages thread.  On every point where the options were (1) go with the 3074 way or (2) a different way, 3074 was chosen.  The 2021 version of 3074 to be precise.
Some examples are chainid (which would have been safe if the sig was over the code), storage (which precludes future safe migration to a smart account except for the narrow case in which the user only signed one contract that is identical to the future implementation), no initcode (no way to mitigate @SamWilsn 's callbacks censorship/griefing attack), no revocation.
No point in debating each point separately.  We already did this in the past 126 messages and it’s ignored.  This thread was a waste of time and didn’t affect the end result.  I hope core devs will be consistent about their past decisions, as this EIP does the same things that were previously voted against in 2021.

Author: matt
Date: 2024-05-15T16:54:03.246Z

You said you supported the original version and the original version supports SSTORE. It’s fine if you don’t want that and I’m not discounting the discussion above, but I think it would be easier to follow this conversation if you’re more specific.

Author: yoavw
Date: 2024-05-15T17:23:16.235Z

Let’s not argue semantics, you know exactly what I mean.  @vbuterin deliberately left certain things undecided, to be determined in this thread.  The entire thread was about these decisions.  Not a single decision was affected by anything said in this discussion.  Vitalik’s message above listed 6 decisions.  6 out of 6 ended up being your preference - the equivalent of the 2021 version of 3074.  Prove me wrong - show a single decision in this list of 6 that isn’t.
Being more specific means repeating everything I ever wrote about 3074 since June 2021 in hundreds of messages.  Thanks but I’m not interested in repeating that discussion.
Your plan immediately after EIP-3074 was included, was to remove the concessions made and bring back the 2021 version that ACD previously rejected.  The current version of EIP-7702 is exactly that.

Author: matt
Date: 2024-05-15T18:07:18.377Z

I don’t know what you mean. What you said makes it seem I have made substantial changes to the EIP. Yes there is a discussion about whether the aforementioned variations should be adopted. The discussion is ongoing. I’m trying to present clients the best proposal I can and we can go from there. It just turns out that it is very close to what was originally proposed.



 yoavw:

Vitalik’s message above listed 6 decisions. 6 out of 6 ended up being your preference - the equivalent of the 2021 version of 3074. Prove me wrong - show a single decision in this list of 6 that isn’t.


There have been plenty of people in this discussion and elsewhere against in-protocol revocation. Most of these points aren’t even relevant for 3074 (e.g. banning storage, initcode or not, etc). The overlap is really the question of the signature format.



 yoavw:

Your plan immediately after EIP-3074 was included, was to remove the concessions made and bring back the 2021 version that ACD previously rejected.


As long as the debate is open, I will continue to push for maximum flexibility of the signature. There is nothing wrong with this. You’ve done the same since 3074 was included: try to get it removed. I don’t fault you for it. Please don’t fault me for fighting for something that I believe is technically superior.

Author: yoavw
Date: 2024-05-15T18:25:16.718Z

matt:

It just turns out that it is very close to what was originally proposed.


You’re taking the proposal out of context.  These decisions were deliberately left open, and you’re making it seem like the original proposal considered them and decided against them by default.



 matt:

There have been plenty of people in this discussion and elsewhere against in-protocol revocation


Revocation is 1/6 that happened to be consistent with the 2021 version of 3074.  How about chainid?  Signing over address rather than code?  Anything at all that this thread changed your mind on?



 matt:

There is nothing wrong with this.


But that’s not what I said.  I said that after 3074 was included, based on adding chainid+revocation to overcome ACD objections, you immediately started working on removing them.
Yes, I’ve been pushing to get 3074 removed, but I have been consistent about it before and after the inclusion decision.  Getting one thing included and then trying to change it to something previously rejected is not the same.

Author: matt
Date: 2024-05-15T18:52:11.219Z

yoavw:

You’re taking the proposal out of context. These decisions were deliberately left open, and you’re making it seem like the original proposal considered them and decided against them by default.


All I know is that the original proposal doesn’t have many of the security features you deem critical. If they were so critical, I would have expected them in that proposal instead of the “insecure” variation.



 yoavw:

Revocation is 1/6 that happened to be consistent with the 2021 version of 3074. How about chainid? Signing over address rather than code? Anything at all that this thread changed your mind on?





 vbuterin:


Should the contract_code signature also sign over the account’s nonce?
Should the contract_code signature also sign over the CHAINID?
Should the contract_code instead be an address? This would save calldata, though only a little bit of calldata because ERC-1167 proxies  only take 44 bytes.
Should SSTORE inside the “temporarily contract-ified EOAs” be prohibited, like it is in EIP-5806?
Should we have initcode and not just contract_code?
Should we just add a flag to NOT set the code back to zero at the end? Thereby making this EIP also supersede EIP-5003.




same as 3074 – should be handled by the code which the account has delegated to.
same as 3074
I don’t recall discussing whether 3074 should sign over code vs. an address. I believe it was always an address. I could misremeber though. I did consider a bit using address in the tuple but still signing over code. The main reason to not do this is you now impose a database lookup on clients before they can determine the signer of the auth tuple. The reason it’s okay to skip signing over chain id is wallets can ensure you only sign to contracts with a deterministic address. This was the same argument for 3074, but we added it because it didn’t feel like such an inconvenience. Now people are requesting the nonce be optional. At that point, we should just drop it altogether.
SSTORE should not be banned because smart contract wallets need to figure out how to deal with storage conflicts today. It’s a known problem and will be solved by the application layer. It’s not necessary to inhibit the protocol by it. Additionally, banning SSTORE means we can not as directly use existing smart contract wallet code. Avoiding “two tracks” of AA development is a main goal of this EIP.
This one I am very conflicted on. In general I prefer not having initcode as it feels weird to run initcode in accounts that have already be “initialized”. On the other, it feels weird to allow anyone to take 7702 auth tuples and force code into your account in contexts that you may not have expected. After much discussion, I feel like setting code directly is still okay to do. In either case, a dishonest user will be able to sign multiple messages and grief people sending 1155 tokens. Honest users / wallets should follow the safe guidelines, and that is to only sign a single 7702 message per account to a proxy contract. That will allow them full flexibility of changing / revoking code, without potential of being griefed.
This is something we might be able to do in the future, but it seems out of scope for pectra at this point.

Obviously this thread and other discussions informed my view. I wasn’t aware of issue with 1155, but I am confident the solution we proposed is suitable. If there is a better solution, we could consider.



 yoavw:

after 3074 was included, based on adding chainid+revocation to overcome ACD objections, you immediately started working on removing them.


I didn’t start working to remove them. Client devs and 4337 devs beginning to ask why the nonce was there. That’s why max nonce has been discussed so much and why there have been other alternative proposals.
I have always been consistent about not wanting these values in the signature. If client teams again decide that they should be in 7702, they will be. ACD is constantly trying to do the best thing possible. That’s why we’re even discussing 7702 in the first place. 3074 was previously accepted and some are upset saying ACD shouldn’t waiver like this. I disagree. Our job is to create the best protocol we can with the information available to us.

Author: derek
Date: 2024-05-15T20:14:46.426Z

Matt, I think it may be too early to push an update onto 7702, given that many of the points you included in the latest update are still controversial.
The fact that Vitalik did not include, say, in-protocol revocation in the original proposal, wasn’t to say that he was proposing that there should be no in-protocol revocation.  We know that he wrote the original proposal in 22 minutes and he explicitly left out many points as undecided, as can be seen in this comment.
Of course you (or anyone) are totally free to open a new PR to propose some updates, but IMO it would be counter-productive since it’s just splitting discussions between the PR and here.
Personally, I think the most productive thing to do is to continue the discussion here, collect all the most highly-contentious points, and then have an in-person discussion in the next ACDE meeting.  I think it would be better to push an update to the EIP after we are all more aligned.

Author: derek
Date: 2024-05-15T21:56:12.569Z

My own takes on some of these contentious points:


Should the contract_code signature also sign over the account’s nonce?


I would be in favor of in-protocol revocation if there was an elegant way to do it.  The nonceManager proposal will complicate the mempool by introducing cross-account dependencies, and the maxNonce+bumpNonce proposal strikes me as inelegant and may lead to unforeseen/unintended consequences down the line.
Therefore, I’m personally in favor of leaving revocation for the account to handle, though I would be OK with maxNonce+bumpNonce too.

Should SSTORE inside the “temporarily contract-ified EOAs” be prohibited, like it is in EIP-5806?

IMO it’s not accurate to say that because smart contract wallets need to figure out storage conflicts today, we don’t have to ban SSTORE.  Most smart accounts today were not written with the assumption that people would set the account proxy to a completely different smart account, whereas with 7702 it could be a common pattern to use the same EOA with multiple 7702 accounts.  For example, most EOA users use multiple wallets today, and these wallets might use different 7702 accounts.
It’s true that existing 4337 accounts don’t use separate storage and therefore would need to be modified if 7702 bans SSTORE.  However, a 4337 account that uses a storage contract would still be able to work as a regular, non-7702 account, so it’s not entirely accurate to say that it would create two tracks of AA accounts.  We (ZeroDev) will likely just maintain one account (Kernel) that uses the storage contract pattern.
TLDR: I’m in support of banning SSTORE to enforce that all accounts use the storage contract pattern, because I think that a lot (most?) users will end up using more than one 7702 accounts, if not concurrently then at least over time.

Author: wjmelements
Date: 2024-05-15T22:49:43.643Z

I want to comment on how the code is to be specified.
Inline code can be large, makes the transactions larger, and will therefore make 7702 transactions cost more gas.
Using a code_address has the problem that different code can be different on different chains and forces CHAIN_ID into the signed hash for safety. This is still better than inline code though.
I want to suggest code_hash instead. This would be fixed-size and so would not require a large gas payment. The hash refers to the EXTCODEHASH return value for accounts. The transaction can be invalid if there is no matching code_hash deployed yet on-chain. The code could be deployed anywhere. Nodes can support the ability to query code by hash and such a design might even save space on code considering the number of duplicate contracts. I can also imagine a way to deliver missing code via blobs but I don’t want to complicate this proposal.

Author: yoavw
Date: 2024-05-15T23:17:41.945Z

matt:


same as 3074 – should be handled by the code which the account has delegated to.



You mean same as pre-inclusion (2021) 3074.  In the current 3074 it is no longer the case but this version is an attempt to go back to it.



 matt:


same as 3074



Ditto.  Not in the current 3074 but going back to pre-inclusion.



 matt:


I don’t recall discussing whether 3074 should sign over code vs. an address. I believe it was always an address. I could misremeber though.



We did discuss it at some point but never mind that.  The point is that the original 7702 proposal signed code, and now we’re signing an address, disregarding the code - like 3074 does.



 matt:

The main reason to not do this is you now impose a database lookup on clients before they can determine the signer of the auth tuple.


Clients don’t need to do this when propagating a transaction, since the sender pays for reverts.  And during block validation they need this database lookup anyway in order to load the code which the transaction uses.  Which operations require clients to do a database lookup for the codehash but not to also load the code for execution?



 matt:

The reason it’s okay to skip signing over chain id is wallets can ensure you only sign to contracts with a deterministic address.


Some wallets will, some won’t. And if you ever used one that didn’t, your address is unsafe forever on every future chain.  No way to revoke, no way to control what the logic will be on new chains.  Seems like a profitable business plan for a new wallet:

Deploy 7702 implementation using CREATE or "CREATE3 "(or CREATE2 with initcode that returns bytecode it reads from state if a certain contract exists).  On current chains the implementation is legit.
Get as many new users as possible by sponsoring their gas for a month.  Target hardware wallet users in particular - they are less likely to change their keys later, and have more assets on average.
Keep collecting those sigs.  Doesn’t matter if users leave a month later - they already signed and cannot revoke.  Doesn’t matter if the users use a hardware wallet, the rugpull-wallet doesn’t need to access the private key, just request the signature.
Wait, possibly for years, until some past users accumulate a lot of assets on other chains.
Deploy a drainer contract to the same address on every possible chain, drain everyone, move to the Bahamas.  Reputation no longer plays a role at this point.

It becomes impossible for HW wallets to protect their users if they ever use it with a not-so-great wallet.
Any reason this “highly profitable business strategy” won’t happen?



 matt:


SSTORE should not be banned because smart contract wallets need to figure out how to deal with storage conflicts today.



I started with the same opinion until I realized it’ll make future migration impractical.  What would be the process for migrating to a permanent implementation?
To make it concrete, let’s say I’ve been using my EOA with a simple batching 7702 contract that writes some storage slots, and then I want to migrate my account to a Safe multisig.  How do I ensure that none of the previously-written slots represents an entry in OwnerManager.owners, resulting in some unknown shadow signers in my Safe?



 matt:


This one I am very conflicted on. In general I prefer not having initcode as it feels weird to run initcode in accounts that have already be “initialized”.



I felt the same initially, until @SamWilsn demonstrated an attack that can’t be mitigated otherwise.



 matt:

In either case, a dishonest user will be able to sign multiple messages and grief people sending 1155 tokens.


I’m not talking about a dishonest user griefing others, but about a honest user being censored by a malicious user:

User1 performs some operation using 7702. E.g. sign some batching contract to submit a batch.
User2 which uses 4337 (maybe even with a contract account) sends a UserOp to transfer ERC-1155 tokens to User1.
Malicious bundler grabs the UserOp from the AA mempool and submits the bundle in a 7702 transaction that sets User1’s code to the batching contract from step 1.
The UserOp reverts in execution because the batching contract doesn’t implement onERC1155BatchReceived (or whatever the callback-ERC-of-the-day is), whereas if it were an EOA it would have succeeded.

After signing that contract, User1 has no way to avoid being denied token transfers.  And User2 has no way to avoid griefing (paying for a reverted transaction that should have succeeded).



 matt:

Honest users / wallets should follow the safe guidelines, and that is to only sign a single 7702 message per account to a proxy contract.


I recall hearing the same statement about 3074 invokers, and yet most of the invokers people wrote don’t seem to work that way.  Most seem to be single-purpose invokers, making the assumption that the user will sign more than one.  Any reason to expect that this time will be different and everyone will follow safety guidelines?



 matt:


This is something we might be able to do in the future, but it seems out of scope for pectra at this point.



Right, and I don’t even disagree on this point.  It just nicely completes the picture of the new version of 7702 being equivalent to (pre-inclusion) 3074.  At every junction, it makes the 3074 choice while disregarding any concerns in this thread.



 matt:

I didn’t start working to remove them. Client devs and 4337 devs beginning to ask why the nonce was there.


Someone forwarded me this message you sent to the 3074 coordination group shortly after ACD voted to include it, which seems to contradict that.
Now that we’ve made it over the inclusion hurdle, it might be possible to chip away at those concessions. But those demands are going to need to come from new participants. Maybe ###### would be willing to make a statement on ACD873×213 51 KB
Reading this made me a bit skeptical about people making statements against these concessions.



 matt:

ACD is constantly trying to do the best thing possible.


Right, but tactics like the above might sway core devs if they’re not made aware of them.
The latest 7702 update seems like a continuation of the same strategy - getting no-chainid and no-revocation past core devs after they rejected it.  I shouldn’t be the one pushing back against it.  Core devs should.  If they choose to be inconsistent about it, I can’t and won’t stand in their way.

Author: matt
Date: 2024-05-16T07:26:07.699Z

It’s honestly sad that you’re trying to publicly vilify me by posting out-of-context telegram messages. I’m going to post the full exchange, because I’m not going to let you defame me, but this is not a constructive way to figuring out how to ship 7702.
Screenshot 2024-05-16 at 10.06.27968×1516 160 KB
Screenshot 2024-05-16 at 10.06.471030×944 91.4 KB



 matt:

I didn’t start working to remove them. Client devs and 4337 devs beginning to ask why the nonce was there.


As I said, external people began asking why the nonce was in the signature. I noted that it may be possible to relax those requirements as people realize how restrictive the nonce requirement is. As ACD is always trying to do the best thing, it’s totally valid to modify EIPs as more people get eyes on it and sit with it. That’s why we’re here trying to push 7702 over the line.

Author: MrSilly
Date: 2024-05-16T11:27:44.953Z

matt:

I’m going to post the full exchange, because I’m not going to let you defame me


Can you explain how the extra context changes the meaning of your message? “Now that we got over the inclusion hurdle it might be possible to chip away at those concessions” still seems like a frank admission of how you’re thinking about the process.
You really can’t understand how others would characterize this as a bait and switch tactic that attempts to exploit the ACD process, leveraging the legitimacy and prestige of “the core devs”?
Bait and switch tactics work because they leverage the psychological desire to appear consistent with ones previous commitments. If you read books on the the dark arts of social engineering (eg “Influence Science and Practice”, “Power of Pursuasion”) you’ll find good explanations of how various persuasion professionals (eg marketers, used car salesmen, cult leaders, lobbyists) use bait and switch tactics to get people to commit to stuff they would otherwise say no to. It’s very effective.
The 2021 version of 3074 was rejected over and over  BECAUSE of all the devilish details that led to disagreement. If you don’t want to be perceived as engaging in bad faith, you can’t get over that hurdle by making “concessions” and then attempting to revert  back to the thing you couldn’t get others to agree with you on before. That just ends up looking like a manipulative attempt to overpower disagreement with underhanded tactics. Important changes should not happen without broad agreement, and it is going to be harder to reach agreement if the other participants  suspect every move you make is some kind of trick. Fool them once, shame on you, fool them twice shame on them.
Feigning outrage when someone calls you out on this behavior is absurd given that you’re attempting to pull another bait and switch right here by proposing a “new” version of 7702 that’s not even a well disguised cut and paste of 3074. Come on, you even left the AUTH and AUTHCALL opcodes:
Screenshot from 2024-05-17 12-40-43893×596 67.8 KB
For those who want to verify this for themselves, the full PR where Matt cuts and pastes wholesale from 3074 is here:
https://github.com/ethereum/EIPs/pull/8561/files/c37305938a3619e00c3ac4d3abe103f8330b6138
Then for emphasis, as if making 7702 functionally equivalent to the rejected version of EIP 3074 wasn’t enough, you change the terminology in the EIP to 3074 language. Except for the invoker contract. That’s now called the authority contract.
When I saw your name on the 7702 proposal I was hoping I had somehow been misreading your intentions for years now, all evidence to the contrary notwithstanding. Wasn’t expecting you to try to cut and paste 7702 into 3074 and then pretend we are having a new discussion. The older worse 2021 version of 3074 no less, with those concessions “chipped away”. That is quite a bold stunt. You have some cahones, I’ll give you that, but you are being so blatant I can’t tell if you’re just trolling or really do have such a low regard for the intelligence of others.
BTW, some subset of people agreeing with you that no nonce was needed was true from day one. The “extra context” you provided showed the people you coordinated with on the 2021 version of 3074 complaining about the nonce. We already knew what version of 3074 they wanted.

Author: matt
Date: 2024-05-16T11:43:11.726Z

MrSilly:

Can you explain how the extra context changes the meaning of your message?


I really can’t make it any clearer:



 matt:

As I said, external people began asking why the nonce was in the signature. I noted that it may be possible to relax those requirements as people realize how restrictive the nonce requirement is. As ACD is always trying to do the best thing, it’s totally valid to modify EIPs as more people get eyes on it and sit with it. That’s why we’re here trying to push 7702 over the line.


Sometimes it takes inclusion to seriously look into proposals. That’s okay. Changing proposals after it’s accepted is okay if it’s agreed upon by client teams.



 MrSilly:

When I saw your name on the 7702 proposal I was hoping I had somehow been misreading your intentions for years now, all evidence to the contrary notwithstanding.


You have and continue to misread my intentions.

Author: MrSilly
Date: 2024-05-16T11:49:28.756Z

yoavw:

Seems like a profitable business plan for a new wallet:

Deploy 7702 implementation using CREATE or "CREATE3 "(or CREATE2 with initcode that returns bytecode it reads from state if a certain contract exists). On current chains the implementation is legit.
Get as many new users as possible by sponsoring their gas for a month. Target hardware wallet users in particular - they are less likely to change their keys later, and have more assets on average.
Keep collecting those sigs. Doesn’t matter if users leave a month later - they already signed and cannot revoke. Doesn’t matter if the users use a hardware wallet, the rugpull-wallet doesn’t need to access the private key, just request the signature.
Wait, possibly for years, until some past users accumulate a lot of assets on other chains.
Deploy a drainer contract to the same address on every possible chain, drain everyone, move to the Bahamas. Reputation no longer plays a role at this point.

It becomes impossible for HW wallets to protect their users if they ever use it with a not-so-great wallet.
Any reason this “highly profitable business strategy” won’t happen?


Non revocable, replayable signatures delegating an EOA to a contract is functionally equivalent to the security concerns with EIP 3074 invokers. Given how likely it is to work, the only way the scenario you outlined doesn’t happen is if wallets whitelist what code you can sign with extreme prejudice. Back to permissioned innovation.
IMHO, we should not be be passing an address to sign, we should be passing code. Yes it costs 30 extra bytes for some use cases, but as others have pointed it it makes the design more expressive and also more secure in that you don’t need to trust code that you delegate to as much because you can drop permissions first. You can let some provider sponsor your gas without your wallet having to whitelist them because the wallet only calls that code in the context of a spending limit. Giving that up to squeeze a few bytes out is a case of premature optimization.

Author: matt
Date: 2024-05-16T11:53:40.501Z

MrSilly:

IMHO, we should not be be passing an address to sign, we should be passing code. Yes it costs 30 extra bytes for some use cases, but as others have pointed it it makes the design more expressive and also more secure in that you don’t need to trust code that you delegate to as much because you can drop permissions first


It makes it more expressive in a way which is not compatible with smart accounts. It is also not possible to let users sign arbitrary code. There still needs to be a whitelist in the wallet, otherwise the user may be convinced to sign code that allows an attacker control of the account.

Author: MrSilly
Date: 2024-05-16T12:25:13.004Z

matt:

Changing proposals after it’s accepted is okay if it’s agreed upon by client teams.


No, if there is still broad disagreement it really isn’t. That was mishandled.

I try explaining why giving special governance powers to client devs is dangerous and ultimately incongruous with our values here:





Reflections on Ethereum governance following the 3074 saga Process Improvement


    Does “core dev” really have a well defined coherent meaning, or is it just some nebulous term we borrowed from Bitcoin, which doesn’t have a governance problem because it doesn’t have any governance. In Bitcoin the question of who calls themselves a core dev is inconsequential. If someone wants the honor fine, there’s no point in arguing with them about it because it doesn’t give them the power to change the rules of consensus. 
Importing this uncritically to Ethereum may bake in some hidden un…
  



Saying it’s ok if the client teams agree is self serving given that you can leverage the authority of the majority client in that circle and other participants can’t. Doesn’t mean your arguments have any more merit.


Client devs should not be in the role of Solomonic kings that pass judgement and settle important disagreements. That’s not how the de-facto emergent consensus governance model we had worked before and I hope ACD calling for the inclusion of 3074 was the first and last time it happens.





 matt:

You have and continue to misread my intentions.


I still hope to be convinced of that. This ongoing dispute around AA is the dumbest waste of super scarce smarts I’ve ever seen in this space. You and Yoav cancel each other out. I suspect your beef was misdirected up until recently because you thought he wrote my protecting governance from special interests post, and maybe by now it’s just a habit. They die hard

Author: matt
Date: 2024-05-16T12:28:55.611Z

MrSilly:

This ongoing dispute around AA is the dumbest waste of super scarce smarts I’ve ever seen in this space. You and Yoav cancel each other out. I suspect your beef was misdirected up until recently because you thought he wrote my protecting governance from special interests post, and maybe by now it’s just a habit.


That is one thing we can agree on. Let’s move forward and focus on the technical merit of 7702 and the open questions. I have written a very detailed rationale for why the decisions made in the EIP are safe. I would like to see more discourse on why those points are wrong or why there is a better approach.
And fwiw I thought it was a troll post from someone else in ACD long ago.

Author: MrSilly
Date: 2024-05-16T12:34:06.214Z

matt:

There still needs to be a whitelist in the wallet, otherwise the user may be convinced to sign code that allows an attacker control of the account.


The code for dropping privileges can be embedded in the wallet itself just like the code for encoding any transaction. Then you don’t have to trust the code you’re signing as much. Ideally if you authorize a contract to pay for your gas it can steal at most your max gas budget. Since the privilege drop would be encoded as part of the transaction, hardware wallets or other WalletConnect like solutions that separate transaction encoding from signing could parse the transaction and show you what you’re signing.

Author: yoavw
Date: 2024-05-16T14:06:47.998Z

Before replying any message, I’d like to clarify an important point.  My personal objection to the current form of 7702 due to bad security trade offs for EOA users, seem to have raised concerns that ERC-4337 will not support it.  I want to reassure everyone - that is not the case.
My current objections are not related to AA.  As long as 7702 is compatible with the AA roadmap and doesn’t degrade 4337, we intend to support it.  The current version is not great for EOA users but will work fine with 4337, so the protocol will support it.



 matt:

It’s honestly sad that you’re trying to publicly vilify me


Not trying to publicly vilify you, just to show that what you wrote is inconsistent with something you wrote in the past.  Something you have done yourself in past debates we had - taking an older message out of its original context and trying to show that it’s inconsistent with what’s being said in a different context.  It’s strange that you take personal offense, given that trying to prove inconsistency is a method you often apply yourself.
Anyway, my intent is not to vilify anyone so let’s move on.



 matt:

is not a constructive way to figuring out how to ship 7702.


Neither are other ways we tried.  Any argument not consistent with 3074 gets brushed off.
As I wrote many messages ago in this thread, I already made my case and debated the trade offs of every point in 7702, so I meant to stop debating and let the community decide based on that.  I had to jump back in because you didn’t wait for the community to reach consensus and just edited the EIP to match your preference.  Had you not done that, you wouldn’t have heard another word from me about revocation, etc.
We both made our case and it seems that further debate won’t get us anywhere.  We should both take a step back, let the community debate it, and only jump in when something is misunderstood and requires clarification.  But you editing the EIP before consensus is reached, is incompatible with that.



 matt:

I noted that it may be possible to relax those requirements as people realize how restrictive the nonce requirement is.


I noted the same thing myself on a 3074 breakout call, long before it was included.  Using the nonce directly is too restrictive and kills many good use cases.  Therefore I proposed maxNonce+bumpNonce during that call.  It never made it to the proposal so no one had a chance to evaluate it as an alternative to nonce or to no revocation.  Those external people you’re talking about didn’t object to revocation in general, they objected to the restrictive revocation method you chose to include in 3074 despite having a less restrictive option.
That’s why I suspected from the start that there will be an attempt to remove it later.  If the intention was to really have revocation in the final version, you would have chosen one that doesn’t restrict use cases.  The “chip away” message just confirmed what I assumed earlier.
In the current thread you stated that your preference for 7702 is no revocation > max nonce > current nonce.  Since max nonce was also proposed for 3074, choosing current nonce seems strange if you intended for it to get included that way.



 MrSilly:

Given how likely it is to work, the only way the scenario you outlined doesn’t happen is if wallets whitelist what code you can sign with extreme prejudice. Back to permissioned innovation.


In the scenario I described, the wallet is the attacker preparing a rugpull.  Therefore it will prompt the user to sign whatever contract it wants.  This hypothetical wallet lets you connect your Ledger, sponsors your transactions for the first month to incentivize you to use it, and keeps the authorization you signed - for a perfectly legit contract that just happens to be deployed via a CREATE3 factory.  After a month it stops sponsoring gas and you move to a different wallet, not realizing that your account is no longer safe.  A year letter, your assets on other chains start getting drained on other chains.  The first wallet effectively stole the private key from your Ledger, despite having never seen the actual key.



 MrSilly:

IMHO, we should not be be passing an address to sign, we should be passing code.


An address is fine as an optimization, if the signature is over keccak(address+code).  The code doesn’t need to be in the transaction if it can be read on-chain.  The problem in the new version is that code was replaced with address rather than a signature over both.



 matt:

I have written a very detailed rationale for why the decisions made in the EIP are safe. I would like to see more discourse on why those points are wrong or why there is a better approach.


I believe I have done that.  And the rationale is still incorrect IMHO.  To take just one example, I have yet to see a flow in which clients will need to perform a database lookup on the account’s code but not to also load the code for execution.  Transaction propagation doesn’t require that, and block validation requires the entire code anyway.  Another thing is that the rationale makes a false assumption that the EIP will only be used in one way - each EOA only ever signs one contract.  That is inconsistent with how people have been building invokers so we have no reason to believe this time will be different.  If the only safe way to use the EIP is “as intended” then the EIP should not make other, unsafe ways possible.
The rationale you added is just… rationalizing why the pre-inclusion 3074 is the right model.  Everything is written in support of that, and any contradicting evidence is ignored.  This may work on those who aren’t that deep in the weeds and may not understand the nuances above.  But you are smart and very familiar with the topic so I assume you do understand.  You just choose to ignore it.

Author: ArikG
Date: 2024-05-16T14:52:23.183Z

Rationale:
I believe that in the long term (3-4 years) - most EOAs will be using a single smart contract implementation (per account).
In the short and even medium term (1-2 years) there will be multiple smart contract accounts being used, and so we will be living in a diverse special-purpose contract world for some time.
One of the great powers of 7702 (inherited from 3074) is the ability to adopt smart contract paradigms gradually.
If every decision we make on 7702 adoption becomes a life long decision - that prohibits us from making these kinds of decisions at all - waiting endlessly for the optimal option. I don’t trust EIP-6900 and EIP-7579 yet, they haven’t been battle tested, but I will want to trust one of them someday. Deciding now if I adopt some intermediate smart contract without modularity or wait until these protocols mature and one of them prevails does not make sense to me. I want to be able to add some gasless/batching contract now and over time graduate myself to possibly also supporting some session keys, and some new capabilities people will invent next year but eventually to adopt a full blow AA smart account towards a transition to full AA.
So I believe there is meaningful value in things like flexible in-protocol revocation and replay protection. It will actually make innovation faster for wallets - because it allows us to do better risk management. Risk management and mitigation is a way to enable faster progress with putting less implications on each decision.
The risk we perceive is that once you sign a 7702 message - you create smart contract risk on your EOA. Having that risk limited/bounded, allows you to innovate more freely. There is a big difference between temporary and indefinite risk.
With all of this in mind, the current opinion on the 6 features is:

Should the contract_code signature also sign over the account’s nonce? Yes, flexible nonce with ability to do both “single transaction authorization” and “indefinite revocable authorization” (e.g. maxNonce+bumpNonce or similar solution)
Should the contract_code signature also sign over the CHAINID? Yes, we (as everyone) currently only sign transactions that can run on a single chain with some protection of cross-chain replay attacks. We like that situation. It is a valuable security measure. Given the use case for cross-chain is limited to very very specific use cases and risk to all actions is not great - we like this protection.
Should the contract_code instead be an address? Unopinionated. But as mentioned in #2, should have some cross chain protection if possible.
Should SSTORE inside the “temporarily contract-ified EOAs’’ be prohibited, like it is in EIP-5806? No. But our opinion on this is not strongly held. It seems like a meaningful limitation for a small edge case already solved by 4337 SCWs.
Should we have initcode and not just contract_code? Unopinionated.
Should we just add a flag to NOT set the code back to zero at the end? Thereby making this EIP also supersede EIP-5003? No. Not in Pectra, due to risk of delays and the learning we will get from seeing this EIP in the real world before fully understanding this transition. It’s good preparation for the future.

This feels as striking the right balance between capabilities and protection and hope it will bring back the conversation to the protocol and get it ready for approval for inclusion.

Author: derek
Date: 2024-05-16T15:12:08.306Z

derek:

Matt, I think it may be too early to push an update onto 7702, given that many of the points you included in the latest update are still controversial.
The fact that Vitalik did not include, say, in-protocol revocation in the original proposal, wasn’t to say that he was proposing that there should be no in-protocol revocation.  We know that he wrote the original proposal in 22 minutes and he explicitly left out many points as undecided, as can be seen in this comment.
Of course you (or anyone) are totally free to open a new PR to propose some updates, but IMO it would be counter-productive since it’s just splitting discussions between the PR and here.
Personally, I think the most productive thing to do is to continue the discussion here, collect all the most highly-contentious points, and then have an in-person discussion in the next ACDE meeting.  I think it would be better to push an update to the EIP after we are all more aligned.


I just want to reiterate that:


I think @matt shouldn’t have opened the PR for EIP-7702 that mostly only reflects his personal takes, when most of the takes are still highly controversial as can be seen in this thread.  The PR is misleading for the community at large, most of whom haven’t had the time to review this whole thread and might think that “we” (whatever that means) have already made certain decisions when we really haven’t.


I don’t believe it’s productive for @yoavw or anyone else to post screenshots or otherwise take this thread to a non-technical direction.  There’s a time and place for governance convos but it’s not in this thread.


Again, I feel both @yoavw and @matt have made their points and preferences clear, and at this point it’s most helpful for others to chime in.  The next step should be to collect these arguments and discuss them in person in the next ACDE call.  How we break the ties after the call if there are further disagreements (which there will likely be), I don’t know, but personally I’d be fine with @vbuterin making the final decisions as the primary author of this EIP.

Author: frangio
Date: 2024-05-16T22:04:59.907Z

matt:

The reason it’s okay to skip signing over chain id is wallets can ensure you only sign to contracts with a deterministic address.


I’m not sure this is easy to check for? Even if the contract was deployed with CREATE2, it can be made to have arbitrary code. To rule that out you need static analysis of the deployment code, and it seems more difficult than checking for DELEGATECALL opcodes (another way of having arbitrary behavior).
Signing over contract address without also the chain id seems risky.

Author: wjmelements
Date: 2024-05-17T18:27:09.693Z

frangio:

Signing over contract address without also the chain id seems risky.


Which is why you should sign over the code hash instead.

Author: wjmelements
Date: 2024-05-17T20:37:32.793Z

wjmelements:

The transaction can be invalid if there is no matching code_hash deployed yet on-chain.


Yet another way to do this could be to sign the code_hash, but specify the code_address in the transaction, so that nodes don’t have to index code by hash.

Author: julrach
Date: 2024-05-18T08:39:43.797Z

As I warm up my debate muscles, I was wondering if it be too naive to propose a block and/or time-based revocation mechanism?
Essentially users would specify the max time that the signed contract_code would be valid. This can be in addition to another set of revocation steps but time is always a constant increasing regardless of your account’s executions on-chain. I’m definitely aware that this doesn’t fully de-risk malicious contract code from being used before the time-based revocation triggers, but this at least provides a solution for not fully “bricking” your account after (unintentionally) max-nonce signing malicious contract code.
Also, would like to say that I support the maximal flexible implementation of what gives EOAs super powers, which is the aura of what we’re trying to accomplish here whether it’s 3074 or 7702.

Author: MrSilly
Date: 2024-05-24T03:22:32.275Z

julrach:

I’m definitely aware that this doesn’t fully de-risk malicious contract code from being used before the time-based revocation triggers, but this at least provides a solution for not fully “bricking” your account after (unintentionally) max-nonce signing malicious contract code.


I’m all for additional safeguards, but note that a sane implementation of Yoav’s max nonce proposal would guarantee at the protocol level that it is possible for users to revoke the permission they gave for a contract to act on their behalf.
Unfortunately, this is not currently what is being proposed in the open PR. If this reckless, insecure version of 7702 is accepted it means we max out the risk of signing a buggy or malicious contract. That in turn strengthens the argument for whitelisting which contracts users can authorize. This won’t be great for new wallets and innovation.
The non-revocable version of 7702 also maxes out the risk from malware that can mess with the operation of even the most trusted wallets . Those who have opposed revocation at the protocol level argue that wallet interfaces have to be trusted anyway, but currently this is not true. The best practice for EOA security is to use secure signing solutions, so you don’t have to trust the integrity of the entire stack from the operating system to the extension running in your browser. Enabling protocol level revocation preserves some of the security guarantees you can get from secure signing solutions (e.g hardware wallets / wallet connect). Signing over a contract becomes less like giving up your private key forever and more like using another interface.
This reduces the risk from your computer getting hacked and also the risk of experimenting with new wallet interfaces. For extra security, we should consider standardizing how privileges are dropped so that secure signing solutions give user visibility into what risks they’re taking by authorizing a transaction. There’s a difference between signing over unlimited power to drain your wallet and signing over the power to pay your gas, or interact on your behalf with a specific DEX contract.
Sometimes users may still want to give wallet interfaces the power to drain their assets, but even then there seems to be a meaningful difference in the kind of attacks irrevocable, unlimited authorizations enable. With revocable authorizations, rugpulls will only effect current users. With irrevocable authorizations, rugpulls effect current and past users.
Note that an insecure version of 7702 will open up a kind of rugpull that wasn’t possible before: the risk of malware injecting code into a wallet interface to backdoor the EOA, even when the user is using a hardware wallet. This should be taken seriously. With a more secure version of 7702 , security conscious users would be to use their hardware wallets to enforce the principle of least privilege and bump up the nonce every time they start using a new computer or a new wallet interface, so that the previous wallet interface doesn’t stay “logged in” to your EOA. Unfortunately, signing 7702 transactions will almost always expose users to considerable risk. Unless you’re using a hardware wallet and manually verifying the authenticity of the addresses of the contracts you’re signing, the main reason for believing your account is still safe is that is hasn’t been drained - yet.

Author: etan-status
Date: 2024-05-30T14:21:31.330Z

How does this interact with EIP-7706: Separate gas type for calldata?

Would we need three new tx types, one for basic (with calldata fee), one for blob (with calldata fee), and one for EOA code (with calldata fee)?
Given that we historically never managed to get rid of a tx type, should we move to EIP-6493: SSZ Transaction Signature Scheme together with this EIP and simply make EIP-7702 an SSZ profile?


For EIP-4844: Shard Blob Transactions there was a restriction that to is required to be set. Do we have a similar restriction for EIP-7702 transactions, or can a transaction deploy a new contract and also replace its own account code during execution?

Author: nlordell
Date: 2024-05-31T13:47:07.004Z

On the “sign code” vs “sign address” debate:
First of all, just wanted to be clear about my current stance that signing an address is fine. IMO It is slightly less expressive and removes some interesting use cases that were possible with EIP-3074, but my personal opinion is not that it is fundamentally problematic. Just wanted to share some my point of view so it is considered for the EIP from a “feature” point of view.
AFAIU, the current rationale around signing an implementation address instead of some template code is that it is shorter (less than half the amount of data - 20 bytes vs 45 bytes for the min-proxy code) and that it does not add any additional value. However, I believe it does add additional value, as it enables keys to sign additional context that is accessible on-chain that can be used in a number of (IMO) interesting cases over the current suggested proxy approach. In particular, it can serve a similar purpose to the commit argument from EIP-3074: some additional piece of data that is included in what ultimately gets signed by the account.
In order to not be super generic, I am going to focus on a particular use cases that I believe directly benefit from signing template code instead of a delegation address: account initialization. Currently, the suggested approach to using 7702 to upgrade an EOA to a SCA is to replace code with the suggested proxy implementation linked above. The proxy then takes care of initialization in the cases where the proxy is being used for the first time. This require the initialization to be authenticated using a signature from the EOA, meaning that all 7702 upgrades require at least 2 signatures (one for the 7702 signature, and one for the initialization). It is possible to reduce this to 1 signature in the case where tx.origin is permitted to set code with some minor modifications to the suggested proxy (it can skip the ecrecover if address = tx.origin), but only without gas sponsorship (since the EOA is the tx.origin in this case).
If we were to sign template code instead of an address then this minor downside can be worked around. Specifically, minProxy(implementation) || commit can be used as the code, i.e. you append some commit parameter to the min-proxy code as some additional metadata that doesn’t actually execute, but can be used on-chain as a source of some additional signed data. This allows flows where SCA implementations can accept initialization without additional signatures and instead compute some hash(initializationParameters) and compare it to the last 32 bytes of the account code with extcodecopy, therefore, enabling EOAs to be upgraded to SCAs with a single signature (even with gas sponsoring). This also unlocks some fringe use cases where, for example, you use Nick’s method to generate random 7702 signatures for single use accounts with a pre-determined initial configuration for which you are guaranteed to not have a private key (although, the actual usefulness of this is questionable at best, however a use case that was possible with 3074).
Again, this isn’t a particularly strong argument to justify “WE MUST SIGN CODE!”, but I wanted to share my slight preference for signing code instead of a delegation address.

Author: sudeepdino008
Date: 2024-06-04T19:15:47.828Z

I’m still not comfortable about optional revocability.

The argument that has been pushed so far is that the signature has same kind of security concerns/handling as a private key or seed phrase. I disagree. Once a tx is made with non-revocable signature, it’s public.
This is different from private key because if I delete a metamask wallet from my browser, the private key is wiped out. It never leaves my computer (I trust metamask to follow this). This doesn’t happen with signature because this is public, and deleting metamask doesn’t quite provide the same effects.
There is a significant change in the level of trust placed on wallet providers here. Of course, smart wallets are more complex than EOAs (and so there’s already an increase in trust), but I still want to able to delete/leave a smart wallet without having lingering doubts about future signature exploitation. e.g. I realize that a wallet provider I was using is not really safe anymore, and I want to do a “revoke all previous authorizations”-style operation – something analogous to what happens when (in web2) I change password or “sign out from all devices.”
There is a shift of trust (regarding security) from Ethereum protocol to wallet providers, which is uncomfortable. Making revocability optional complicates the UX, and some wallet providers might just decide to make all signatures non-revocable in order to “simplify the UX” and not expose the revocable signature option at all.

Author: frangio
Date: 2024-06-06T00:56:08.328Z

As discussed in the last breakout room for this EIP, revocation by account nonce is incompatible with valuable use cases. Optional revocability is proposed as a compromise, but there doesn’t seem to be a consensus in favor of it.
My feeling is that the current design tackles the problem of revocation from a weird angle. The incompability between nonce-based revocation and 7702’s AA goals seems fundamental.
Instead of relying on nonces, an ideal revocation mechanism for 7702 would allow users to express that they no longer authorize a particular address as code for their account.
Could we add a new system contract to track revocation of authorized addresses? Accounts would be able to call into this contract to revoke an address. Clients would have to look up revocation status in the system contract to check the validity of a 7702 authorization. This extra lookup would incur a cost, and 7702 transactions should be priced accordingly. I don’t think it’s unreasonable or too discouraging to charge a little extra for this.
Update: See proposal

Author: nlordell
Date: 2024-06-06T10:23:12.395Z

Another potential use case for EIP-7702 would be permissionless deterministic CREATE2 deployments. The current status quo is to either use something like Arachnid’s or MicahZoltu’s CREATE2 deployer, or something like the Safe singleton factory.

The Arachnid/MicahZoltu CREATE2 deployer is deployed using a transaction generated with Nick’s method, making it completely permissionless at the cost of making the transaction completely sealed. This means that it cannot contain any chain information, or change things in the future such as gasLimit or gasPrice. This is a pretty big downside for new chains since not all chains support non-EIP-155 transactions (so transactions without chain ID replay protection which is required by this method), and some chains may have current gas prices that make the transaction unable to be included at a specific time, or even worse, have a different gas schedule which could potentially make the transaction revert and make the CREATE2 deployer lost forever.
The Safe singleton factory works around this by having the team hold a private key and deploy the CREATE2 deployer on request to new networks. While this allows for flexibility in the transaction parameters to ensure that it is valid at the time of deployment, it is far from perfect: it is permissioned (the Safe team holds the private key), and user errors could cause the private key to sign and execute a transaction that would revert and, again, cause the deployer to be lost for ever for a specific chain.

With EIP-7702, a truly permissionless CREATE2 deployment system can be done where you use Nick’s method to sign an EIP-7702 autorization over the bytecode of the CREATE2 deployer with chain ID of 0 and nonce of 0 (so valid for any chain and nonce 0). Then, CREATE2 contract deployments would be done by executing EIP-7702 transactions using the aforementioned authorization. This would be without any of the downsides of the other CREATE2 deployment methods:

It is fully permissionless like the Arachnid/MicahZoltu CREATE2 deployer
It is not lost forever if a transaction would revert (because of different gas schedule in new chains or protocol updates in the case of the Arachnid/MicahZoltu CREATE2 deployer or user error in the case of the Safe singleton factory)
It is not subject to gas fluctuations at the time that a CREATE2 deployer is needed but not available

Note that this requires signing code instead of an address, and allowing non-chain-replay-protected EIP-7702 authorizations. I think there is consensus that allowing non-chain-replay-protected EIP-7702 authorizations is a good idea, but AFAICT the current consensus is that EIP-7702 authorizations should sign addresses and not code.
My stance remains that I don’t think EIP-7702 should be blocked on the “sign code” vs “sign address” debate, but I do find signing code to be more expressive and enable novel use cases that signing address does not, and if the only argument for signing an address is that “signing address leads to slightly smaller transactions and slightly lower gas costs”, I don’t think it is a strong enough argument for choosing to sign addresses instead of code, and hope that the decision is reconsidered.
image552×452 29.7 KB

Author: mds1
Date: 2024-06-06T15:54:29.470Z

Thanks for this write up @nlordell, I’d like advocate for supporting this exact use case.
There is still no tradeoff-free solution to deterministic deployments across chains. It’s a pain point that many teams have, and solving this problem is a very valuable use case that I’d love to see supported by this EIP. A create2 precompile was discussed but never implemented, and if EIP-7702 supports signing over code, we effectively get that for free.
I see four paths to supporting this:

Change back to signing code instead of an address.
Implicitly support signing both addresses and code: The smallest possible delegatecall minimal proxy is larger than 20 bytes, so if the data is 20 bytes treat it as an address, and if it’s any other length treat it as code.
Explicitly support signing both addresses and code, by adding an additional parameter to the tuple that specifies how to treat the data.
Sign a code hash as suggested above by @wjmelements

Author: wjmelements
Date: 2024-06-06T22:03:24.909Z

Guys, I have already suggested a better solution than both signing code and signing code address: sign the code hash but specify the code location in the transaction. This addresses everyone’s concerns, and has all the benefits of signing over code without putting the code in the transaction.
I don’t want to see the main adoption using minimal DELEGATECALL proxies just because you guys didn’t read my posts in this thread.

Author: mds1
Date: 2024-06-07T14:05:18.271Z

Thanks, I’ve edited my above comment so include this option so it’s comprehensive. I don’t feel strongly on the approach used to support deterministic deployments.
To support deterministic deployments though, you’d have to only sign over code hash and not an additional address. If signing over an address you cannot rely on Nick’s Method to specify an arbitrary signature that recovers to a fixed authority, because the address containing the required code hash might differ per chain.

Author: wjmelements
Date: 2024-06-07T19:41:47.435Z

mds1:

you’d have to only sign over code hash and not an additional address. If signing over an address you cannot rely on Nick’s Method to specify an arbitrary signature that recovers to a fixed authority, because the address containing the required code hash might differ per chain.


Yes, this is why you only sign over the code hash and not the address. The address with the corresponding codehash is supplied to the top-level transaction instead of the codehash. So to be explicit, the codehash is only part of the 0x05 (auth) signature and the code address would only be part of the 0x04 (tx) signature. Thereby, the code location can be different on different chains, but the authentication is tied to the codehash.

Author: islishude
Date: 2024-06-11T00:36:59.666Z

If nonce list item is length one, verify the nonce of authority is equal to nonce.


does it mean that the nonce of the authority will be increased?

Author: jflatow
Date: 2024-06-11T15:34:28.795Z

Can anyone who knows please explain the justification for

It will In the case of multiple tuples for the same authority, set the code specified by the address in the first occurrence.

from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md#behavior?

Author: mattstam
Date: 2024-06-12T21:04:42.960Z

The most impactful improvement will be the ability to do multicall writes, e.g. doing WETH.approve() and Pool.swap() in a single TX.
Presumably the way this is supposed to work in EIP-7702 is that you set your contract code to some contract that enables this.

Does this work out of the box with existing wallets (e.g. gnosis safe)?
If not 1, then what does an implementation of this look like?

Author: jflatow
Date: 2024-06-12T22:34:55.059Z

FWIW, definitely agree that non-chain-replay protected authorizations are important. We would want to use the chain id 0 that is currently proposed to support chain abstraction, and having the option at the application level is nice. Invalidation/revokability seems less clear, I could see an argument for having time based expiration instead of nonces. If users have to actively revoke to be protected from contracts that collect authorizations for years and then suddenly steal assets, it doesn’t seem like they’ll be all that much more protected in practice.

Author: nlordell
Date: 2024-06-14T11:34:39.216Z

EIP-7702: Set EOA account code EIPs core


    Guys, I have already suggested a better solution than both signing code and signing code address: sign the code hash but specify the code location in the transaction. This addresses everyone’s concerns, and has all the benefits of signing over code without putting the code in the transaction. 
I don’t want to see the main adoption using minimal DELEGATECALL proxies just because you guys didn’t read my posts in this thread.
  

Oh nice! Yes I had missed this proposal, and yes it does solve the issue of implementing a permissionless CREATE2 deployer which is awesome. Not to mention, it helps with some x-chain issues around “is this code the same on all chains” which is a nice side-effect.
It still doesn’t solve the usecase I described in:




EIP-7702: Set EOA account code EIPs core


    On the “sign code” vs “sign address” debate: 
First of all, just wanted to be clear about my current stance that signing an address is fine. IMO It is slightly less expressive and removes some interesting use cases that were possible with EIP-3074, but my personal opinion is not that it is fundamentally problematic. Just wanted to share some my point of view so it is considered for the EIP from a “feature” point of view. 
AFAIU, the current rationale around signing an implementation address inst…
  

Notably, users would need two signatures to turn their EOA into an initialized smart account, but this is acceptable. We’ve cooked up some clever ideas on making 7702 work with Nick’s method (by encoding context in the r value of the signature), so really the “two signatures for using an EOA as a smart account” is the only downside left.
All in all, I much prefer signing code hashes to addresses as you suggested. That being said, I still very slightly prefer signing code as it is more expressive and may enable use cases that we haven’t thought about yet, but would be very happy if there was a decision to sign code hash instead of addresses.
To update my meme:
image552×452 73.8 KB

Author: mattstam
Date: 2024-06-16T14:51:00.052Z

Seriously, is there any reference implementation yet? This EIP is concerningly far along without any example using contract_code to do a batched TX / multicall write, when that is stated to be the first issue it aims to solve:

Batching: allowing multiple operations from the same user in one atomic transaction. One common example is an ERC-20 approval followed by spending that approval, a common workflow in DEXes that requires two transactions today. Advanced use cases of batching occasionally involve dependencies: the output of the first operation is part of the input to the second operation.

Author: julrach
Date: 2024-06-16T15:34:15.410Z

mattstam:

Seriously, is there any reference implementation yet?


The Otim team is almost done with the 7702 Reth implementation and is working on all necessary base case contract reference implementations in parallel. They are built with the current spec in mind (hence contract_address ). We will be posting about this all soonTM.

Author: matt
Date: 2024-06-17T15:49:34.756Z

sudeepdino008:

The argument that has been pushed so far is that the signature has same kind of security concerns/handling as a private key or seed phrase. I disagree. Once a tx is made with non-revocable signature, it’s public.
This is different from private key because if I delete a metamask wallet from my browser, the private key is wiped out. It never leaves my computer (I trust metamask to follow this). This doesn’t happen with signature because this is public, and deleting metamask doesn’t quite provide the same effects.


I think the argument is slightly different. It’s not the signature that is like the private key, it’s making the signature that is similar to handling a private key. You won’t just throw you private key into some random text box, just like you wouldn’t sign some random 7702 sig request that comes your way (and wallets shouldn’t even allow you to make such a sig).



 sudeepdino008:

I still want to able to delete/leave a smart wallet without having lingering doubts about future signature exploitation. e.g. I realize that a wallet provider I was using is not really safe anymore, and I want to do a “invoke all previous authorizations”-style operation – something analogous to what happens when (in web2) I change password or “sign out from all devices.”


This is certainly possible if smart wallets are designed to support it or if you are sure to always sign over revocable signatures.



 sudeepdino008:

Making revocability optional complicates the UX, and some wallet providers might just decide to make all signatures non-revocable in order to “simplify the UX” and not expose the revocable signature option at all.


Fortunately we’ve seen wallets and infra providers ban together to do the “safe” thing with chain id. Today it is very difficult to include an non EIP-155 tx on chain. I don’t see why providers would do something considered unsafe to “simplify UX”. I think not signing the chain ID is certainly simpler than thinking about which network you’re on.
It’s also worth noting again that signing an unrevocable 7702 auth is not neccessarily unsafe, it depends what the EOA delegates to.

Author: sudeepdino008
Date: 2024-06-18T09:26:08.834Z

I think the argument is slightly different. It’s not the signature that is like the private key, it’s making the signature that is similar to handling a private key. You won’t just throw you private key into some random text box, just like you wouldn’t sign some random 7702 sig request that comes your way (and wallets shouldn’t even allow you to make such a sig).

Let the “authority code” which user authorizes be called template. The wallet providers/products are under much more scrutiny from rest of the ecosystem to be safe and provide the “right” safety measures (as it should be). The template ecosystem on the other hand is more widely open, it is the wild west similar to the general smart contract ecosystem on Ethereum today. Even if wallets whitelist safe templates, and present warnings to user when signing a non-whitelisted template, users can (and will!) sign such templates. If an attacker owning an upgradeable proxy template manages to get a user’s authorization to such a template, the attacker can practically do anything by then swapping the implementation. This grants the malicious implementation power to CALL any other smart contract with (msg.sender = EOA).
The mental model seems to be that if user does such a mistake, they have to bear the consequences. But IMO account abstraction is a lot about providing safer, error-recoverable experiences to user, and it should extend to stopping users from shooting their own foots in cases they inadvertently expose themselves to risk.
The caveat here is that I might be assuming certain things about who owns the templates and if the user can interact with templates outside the purview of wallets. I would like to know your thoughts on that.

This is certainly possible if smart wallets are designed to support it or if you are sure to always sign over revocable signatures.

In general I’ve become fine with the idea to trust my wallet (not forever though). I can trust the wallet to provide a “revoke previous authorizations” feature. Without in-protocol revocation, it means I’ve to depend on the template code having appropriate logic to respect such a revocation. If the template codes are minimal proxy or an implementation (as it probably would be) + template code has revocation mechanism, this is fine.
As for “always sign over revocable signatures”, if the method is optional nonce, I responded to that in the my next comment.

Fortunately we’ve seen wallets and infra providers ban together to do the “safe” thing with chain id. Today it is very difficult to include an non EIP-155 tx on chain. I don’t see why providers would do something considered unsafe to “simplify UX”. I think not signing the chain ID is certainly simpler than thinking about which network you’re on.


It’s also worth noting again that signing an unrevocable 7702 auth is not neccessarily unsafe, it depends what the EOA delegates to.

The issue with optional nonce stems from the feedback we got from wallet providers — i) accounts will be used as both EOA and smart accounts, and ii) most of AA use cases rely on long-standing authorizations. So with a nonce-based-revocable-signature, an EOA tx might inadvertently end up revoking an authorization. It seems to me that because of this wallet design space would be pushed to a scenario where revocable signatures are second-class citizen, as nonce revocability is not compatible with AA use cases.

Author: matt
Date: 2024-06-18T12:30:30.761Z

sudeepdino008:

The caveat here is that I might be assuming certain things about who owns the templates and if the user can interact with templates outside the purview of wallets. I would like to know your thoughts on that.


Ultimately I don’t see a safe way to allow users to sign untrusted templates, even with substantial friction in UI. This is similar to today where almost no wallets allow blind signing arbitrary signatures (yes, they allow blind signing, but it is scoped to a 191 message or tx data – this is an important distinction).
If users may sign arbitrary templates then I agree with you completely and there will funds lost.



 sudeepdino008:

So with a nonce-based-revocable-signature, an EOA tx might inadvertently end up revoking an authorization. It seems to me that because of this wallet design space would be pushed to a scenario where revocable signatures are second-class citizen, as nonce revocability is not compatible with AA use cases.


Yes it’s possible with nonce-based-revocable-signature you may inadvertently end up revoking an authorization. However, there are many application-layer mechanisms which could be used to avoid such cases. This is actually a similar issue that smart accounts have today, which is syncing the authorization scheme across networks. A proposed solution is a simple keystore rollup which stores the authorization logic for user account and it can be pulled in efficiently on all networks. This concept could be extended to notify other EOA wallets that a user has an outstanding 7702 signature.
I don’t think I would go so far to say that nonce revocability is not compatible with AA though. In the happy case, your wallets should be able to use your account exactly as an AA wallet via 4337 or a centralized tx bundler. There is no need for the EOA to send a tx in this scenario (except to revoke).

Author: frangio
Date: 2024-06-18T13:34:55.546Z

matt:

This is certainly possible if smart wallets are designed to support it


My concern is that if revocation is stored in the account itself it’s difficult to ensure a template stays revoked forever. It’s not a property one can verify for a template, it’s a property that has to hold for all of the templates the EOA will ever authorize. Undoing a revocation can be done quietly if it only takes an SSTORE.
By storing revocation status in another contract it would be possible to avoid this issue, but I don’t know if this can be made compatible with ERC-4337/7562 validation rules.
Another approach to avoid this issue is to only ever sign one authorization, for a proxy. If this will be the recommendation, I don’t know why EIP-7702 is so general, let’s just hardcode this into the protocol.
Additionally, there is no “true revocability” because the ability to load the code into the account will remain, even if the code can be made to reliably revert. Whether this has practical consequences is debatable, but it doesn’t feel right.
I don’t want in-protocol revocability to be too heavy-handed, but I’m not a fan of the current compromise either.
I proposed an alternative revocation mechanism that I think has better properties: Update EIP-7702: Add system contract for revocations by frangio · Pull Request #8631 · ethereum/EIPs · GitHub. Please review and leave comments (cc @matt in particular).

Author: matt
Date: 2024-06-18T17:46:11.047Z

What you’re proposing can (and I think should) be done by an ERC. For that reason I don’t see a reason to introduce the complexity into the protocol.

Author: frangio
Date: 2024-06-18T21:02:34.430Z

Yes I believe that’s mostly true, except for preventing revoked template code from being loaded into the account.

Author: 0xkvn
Date: 2024-06-19T08:31:04.858Z

Hi all,
Here is Ledger’s proposal regarding EIP-7702, both from a wallet provider and a hardware wallet with limited computation perspectives:
1- Signing contract code (if it’s still debated)
It would be extremely difficult for Ledger to implement EIP-7702 if we were to use signed contract code. For security reasons, we will have to implement a whitelisting mechanism, preventing the full use of the feature anyway and probably falling back on allowing an ERC-1167 minimal proxy + some known implementations.
We have no way to recognize bytecode dynamically with only the device, so our best option is to focus on the implementation address in order to make it clear and understandable at the signature stage that you would be signing a long lived authorization to transform your EOA into a Smart Account of X/Y/Z brand.
2- Revocability
It seems mandatory to us to have a revocation mechanism, and having a nonce/maxNonce based one seems impractical for everyone, from builders to users.
We want our users to have the freedom to go the AA way, but not in a way that would force them to understand some very complex protocol mechanism and where 1 signature can become a forever problem.
3- Multiple authorizations at a time
Having the possibility for software wallets, DApps or Bundlers/sponsors to keep multiple authorizations for a same EOA, making it possible for them to behave in multiple ways for a same transaction intent, is definitely something that worries us in terms of both UX and security. Since most AA implementations will make you sign personal messages or EIP-712 messages for those intents to be sponsored somehow, that means our devices will never be able to tell you exactly what you’re doing since we have no way to predict what 7702 authorization will be used once reaching the sponsor which can make that message act differently with every AA implementation.
Here is our proposal at a flow that would make sense to us in terms of UX and that might allow us to display things correctly and securely on our devices:
Our understanding is that we could have a short lived authorization message as long as it’s not expected to be added to every single type 4 transactions. If true, then the signature could be based on keccak(MAGIC_BYTE || rlp([chain_id, nonce, address])) almost as the last version of the EIP is proposing but with a mandatory nonce.
Now a mechanism similar to ERC-1967 could then be used to fill a specific storage slot on the EOA’s storage with the implementation address signed with that authorization (something like keccak256('eip7702.transient.implementation')) as long as the authority has no code already. The user will now have to send that authorization and an initialization calldata for that implementation as transaction type 4 in order to “activate” the AA behavior, making the nonce increase and the authorization unusable. Accepting to use SSTORE & SLOAD on the EOA is then mandatory obviously.
At the protocol level, the expected behavior when dealing with a type 4 transaction would then be to verify before any (*)CALL whether or not this slot contains an address for its target/recipient, and if it has, load it in a transient manner as its contract code just like the actual EIP is proposing.
If this brings too much complexity to do it for every recipient of a (*)CALL on the fly, then providing a simple list of address at the transaction level could be an option, just like the access list of EIP-2930 for example.
Any transaction of type < 4 would ignore that mechanism and continue acting like the account is an EOA, making the transition to AA “optional” and not forcing users to spend more gas if they’re not actively using an AA feature (like batching or delegated keys).
At the device level, it would then be possible to provide a storage proof like described in EIP-1186 for that specific slot before signing something and that could give the necessary context in order to verify that an address handled by the device should behave like an X/Y/Z implementation instead.
Good points about this proposal:

It’s revocable anytime. Just sign a new authorization message with address(0) and you’re back to the original behavior (minus the storage used by the implementation)
Upgradable anytime as well, and even auto upgradable directly from the implementation, just like any AA proxy
It’s long lived, you sign an authorization once, you’re good until you decide to update that storage slot again, and it’s not up to a software wallet / DApp / Sponsor to keep those powerful messages
Limit EOAs to 1 implementation at a time → Way easier for the context of a wallet, and can answer EIP-5792 capabilities in a clear way by checking that specific storage slot.
“Clear signing” (ledger[dot]com/blog/securing-message-signing) is back to recognizing a simple implementation address and not recognizing bytecode, while being as little centralized as possible by relying on a storage proof in order to switch from 1 behavior to another.

More controversal:

It’s using SSTORE & SLOAD
Something else ?

As a last comment, this message should not be considered as an endorsement from Ledger to support 7702, but more as a lead into something that looks more manageable for us.

Author: SamWilsn
Date: 2024-06-19T19:38:58.096Z

0xkvn:

It would be extremely difficult for Ledger to implement EIP-7702 if we were to use signed contract code. For security reasons, we will have to implement a whitelisting mechanism, preventing the full use of the feature anyway and probably falling back on allowing an ERC-1167 minimal proxy + some known implementations.


How do you envision dapps communicating 7702-style authorization tuples to the Ledger? I think the only standard interface being discussed right now (bear in mind that I’ve been out of the loop for a while ) is EIP-5792. Ledger would need to pick the bytecode to use anyway, so no different than a whitelist.

Author: SamWilsn
Date: 2024-06-19T19:44:53.030Z

How’s this for a revocation mechanism:

Use initcode (either in the transaction or by referencing a deployed contract.)
Transaction reverts if any of the initcodes don’t begin with a specific bytecode prefix, implementing “call into well-known nonce manager, propagate revert.”
Nonces are handled by EVM.

This gives us the maximum amount of future flexibility (revocation is handled purely by the EVM), and mandatory revocations today.