EIP-7702: Set EOA account code

It’s bullet 1) in behavior section.

The idea is that you can delegate to an empty account if you want to “remove” your delegation. I haven’t been convinced of a reason to add additional mechanisms to the EIP to truly clear the delegation.

SELFDESTRUCT only works for contracts created during the transaction, so I’m not really sure how this would be an issue?

Delegations can definitely be batched, not sure why you believe otherwise? The 7702 tx object has a list field for authorization tuples.

  1. lolwhoops

  2. I’m more worried about the “denormalization” associated with creating two distinct states of undelegated EOA and the future pitfalls that might result in. I’d argue that setting a delegation and then unsetting it should leave an EOA in a state indistinguishable from never having delegated at all. For example, what should EXTCODESIZE return for an EOA delegated to an EOA delegated to an empty account? 0, or 23? (For that matter, what should EXTCODECOPY return?)

  3. Thanks, I missed that EIP-6780 was a thing, which also addresses my previous question about delegation-to-SELFDESTRUCT.

  4. I described this poorly, apologies. I mean that with EIP-3704 a contract could, for example, calculate a new address ecrecover(keccak256(MAGIC || 0 || 0 || contractAddress || salt), 0, 0xdeadbeef..., 0xdeadbeef...), AUTH for it, and then AUTHCALL into it, all within a single method call. With EIP-7702, delegations can only be set via a transaction initiated by an EOA, so the contract will need to calculate the authorization tuple and then somehow ask someone nicely to include it in a TX before it can get on with its business. This would force contracts to break up otherwise-atomic operations and leverage an external market set up with economic incentives for TX builders to include authorization tuples for delegations that contracts need set. That’s not impossible, but it’s certainly a PITA,

Yes indeed current 7702 does not solve universal cross-chain contract deployment. :confused:

This proposal would fix that:

Was it considered? If so is there a reason why it was rejected?

It would be really good to finally solve this issue.

2 Likes

I’m not thinking specifically about deterministic cross-chain contract addresses; I’m thinking more in terms of a single contract wallet with siloed sub-accounts for security purposes. Like it or not, the address is the fundamental security principal, and the ability for contract wallets to easily spin up alternate addresses for interaction with various dApps or protocols would be a pretty killer feature.

(Also could be useful for privacy purposes! ZKPs would allow a contract wallet to manage separate pools of funds for separate people, while keeping the records of the who controls what off-chain.)

Sorry, my post was unrelated, I want to discuss deterministic addresses separately.

I think we’re missing some cost issue in EIP-7702:

Currently, there are 2 possible costs per authorization entry:

  1. PER_EMPTY_ACCOUNT_COST (25000) - the cost a new authorization struct, making an EOA a delegate the first time (equivalent to the gas cost of one storage slot change and one new storage cell)
  2. PER_AUTH_BASE_COST (2500)- the cost of specifying a do-nothing authorization, with the same delegate, or with wrong signature/nonce (which covers roughly the ecrecover)

However, there is a 3rd case:
3. The cost of changing an existing account to a new delegate value.

AFAIK, the last case currently costs 2500, since the delegate already exists, and thus it is underpriced (it has to cause 2 slot changes, one for nonce and one for code (prefix+address).

Hey, I was going through the EIP. Since authorization doesn’t have a way to allow granular control, wondering how we could authorize the specific permissions to the wallets.

The concept of specific permissions is an application-layer one and must be handled by whatever contract an EOA delegates to.

1 Like

I like the 0xef01 designator pattern. I would like for the pattern to be available to all outside of eip-7702 transactions; it should be permissible to CREATE them, but they are currently banned by EIP-3541: Reject new contract code starting with the 0xEF byte

1 Like

As proposed, users can include authorizations with malformed ECDSA signatures (invalid y_parity/r/s values) that are not valid on any chain even in theory.

While authorizations may not be relevant to the current chain (chain_id mismatch), I don’t see why they should allow for arbitrary data storage (256bit chain_id, 20byte address, 64bit nonce, 256bit y_parity, 256bit r, 256bit s; total 156 bytes) using a separate pricing model from those actually intended for data storage. By checking the signature for validity (as in, it at least in theory belongs to some address on some chain), the use case of including a couple extra authorizations for other chains still allows exotic bridge scenarios but at the very least limits the possible wasted storage.

Is there a reason why invalid authorization signatures don’t make the transaction invalid?

These things are all well specified in the EIP. Delegating to an empty account will make the account indistinguishable from one that has been delegated to for intents and purposes.

I think you may be misunderstanding the purpose of 7702. It’s to allow users to delegate to a smart contract wallet and then perform smart contract wallet operations like batching calls, etc. Other use cases, like synthetic accounts from contracts, are not a focus. Once a user has delegated their account, it effectively behaves like a smart contract wallet and they can install custom modules to address any further needs they have.

To do something like this you would delegate the EOA master account to a smart contract wallet and that smart contract would just deploy subaccounts that are controlled completely by the master account.

The second case is intended to be the cost of updating the account for the delegation. What should the true cost of this be? Open to modifying it, but I don’t think we need a third case. Submitting invalid do-nothing updates can just cost the same as a valid update.

The idea is to make transaction validity as simple as possible to verify. I don’t see a reason overcomplicate it so long as the data isn’t cheaper to shuttle inside an invalid 7702 auth.

The idea is to make transaction validity as simple as possible to verify

Could there at the very least be a check on y_parity to only allow [0, 1]? Right now, that field is documented to support any uint256, and limiting the range of y_parity is trivial, even if one wants to avoid the full ecrecover cost in this spec.

Or, at the very least, to a uint8

No, it wouldn’t, at least not by the current language in the EIP:

For example, EXTCODESIZE would return the size of the code pointed to by address instead of 23 which would represent the delegation designation. CALL would similarly load the code from address and execute it in the context of authority.

In case a delegation designator points to another designator, creating a potential chain or loop of designators, clients must retrieve only the first code and then stop following the designator chain.

EXTCODECOPY on a delegate A to another delegate B would therefore perform a code lookup for A, recognize the delegation designator, and perform a second lookup for B. It would then not follow the second delegation, returning the raw contents of the delegation designator at B and allowing observation of B’s delegation target address.

I understand that EIP-7702 was not authored to support this use case specifically, but it is intended to replace EIP-3074. That EIP, though probably not written with this usecase in mind, does support it, and so it’s a relevant point of comparison between the two.

Deploying a ERC-1167 proxy costs ~65k gas upfront and slightly increases the gas cost of each subsequent call. Using EIP-7702 to set a delegate using a deterministic signature will cost ~25k gas upfront and add no additional overhead to each transaction. This seems like it would instantly become the new meta for proxy deployment, and it would be beneficial to consider how automation of authorizations will be handled upfront. The economic incentives mean that it will happen on its own eventually, but IMHO it would be better for the whole ecosystem to specify a standard mechanism rather than deferring to (yet another) bolted-on transaction-submission marketplace.

Wouldn’t an authorization with an invalid signature just not store anything? The TX itself doesn’t have to be invalid, it just won’t mutate state. Or are you talking about the cost to fullnodes of archiving the raw TX rather than on-chain state? (And if so, how would this be different than a TX with a lot of calldata that reverts with OOG?)

Delegating to B isn’t an empty delegation though. You would need to delegate to a known empty + unknown address like 0x0.

It isn’t intended to perfectly replace 3074. The exact complaint about the feature you are mentioning is that it creates a new account for flow separate from the AA flow that has been in development. We can’t have everything and this was the compromise made with the AA community.

If the cost is out-of-whack maybe we can adjust to bring it more in line. I have wondered if we could add a CREATE3 which would allow us to deploy this “protocol proxy”. My main concern is applications using this format to deploy contracts used by many people. This will circumvent the original goal of 3607.

Yeah, I’m worried about providing incentives to abuse it. A legitimate authorization has a chain_id < ~2^52, a y_parity value of 0/1 and fills the rest. An illegatimate data storage may use the full 2x 256 bits for chain_id / y_parity, and so on.

The difference to calldata is that calldata is still paid for, at its intended rate, even if it reverts. While a legitimate authorization requires less storage than an illegitimate one, but is charged the same price as a smaller, legitimate authorization.

I can see lightclient’s argument that indeed, an invalid signature should indeed not make the entire tx be invalid – it should at least be possible to charge for the ecrecovers involved in validating it. But I’d like to see chain_id limited to uint64, and y_parity to 0/1 or at least uint8 so that the illegitimate use case does not offer more data storage than a legitimate authorization.

IMO the key is that the cost for an auth is greater than the cost of calldata, otherwise we risk the free DA as you mentioned.

It seems like there is overwhelming demand to limit the chain id and y_parity. I can accept that limit them to uint64 and uint8.

2 Likes

If Bob has an EOA and Alice deploys an EOA and delegates to Bob, Charlie can run EXTCODECOPY on Alice’s account and get back the contents of Bob’s code. If Bob’s not delegated at all, Charlie gets a zero-length result. If Bob instead delegates to 0x0, Charlie gets 0xef0100000000000000000000000000000000000000000000000000. In fact, one could write a contract that used this as an access-control measure – which probably means someone will, thinking that an EOA that’s never delegated is more secure or some such – and that fact could discourage users from taking the “irreversible” step of delegating in the first place.

Hey, I’m not against cheaper costs here – IMO everyone would benefit from an optimization for the minimal proxy use-case, and it makes sense that it would be cheaper as a delegation mechanism like this would be much cheaper for nodes to process than actually executing the ERC-1167 bytecode. Your point about 3607 is well-taken. I expect that a majority of contract authors would happily take that security tradeoff for the gas savings, so it’s worth considering how to avoid presenting them with the choice.

(It’s also worth pointing out the EIP-3702 doesn’t have this issue, but only because it doesn’t enable this usecase.)


There’s an argument to be made that we should intentionally break the proxy usecase to maintain EIP-3607 protection. I don’t think it’s a good argument, though; I’ve tried to think of what modifications to this EIP could be made to prevent it from being used to deploy proxies, and all of them have significant undesirable impacts.

  1. Raise PER_EMPTY_ACCOUNT_COST to match the gas cost of deploying an ERC-1167 proxy.

This would effectively make opening an AA account several times more expensive than it should be just to discourage people who aren’t even in target users from shooting their own feet on a regular basis, which seems like a perverse set of incentives. The current 25,000 gas cost is in the ballpark of the 21,000 base gas for making a transaction; one can easily justify the small marginal cost of opening a contract-wallet AA account instead of a regular one. I don’t have the exact numbers in front of me but a minimal proxy contract ~3 times that much; raising the cost to prevent the use of EOAs as cheap proxies would have to also raise the barrier to AA by several times.

  1. Prohibit delegations from EOAs with a nonce equal to 0. This would indirectly require at least two signatures to be made by an EOA’s keypair, preventing the use of an EOA derived via the deterministic signature method.

Not only would this cause a gas-sponsorship chicken-and-egg problem, since you’d have to get ETH into the EOA to pay for the initial nonce-bumping TX before you could set delegation to an AA contract wallet with a sponsored gas arrangement, I’m not sure it would even actually prevent the deployment of proxies via EOA delegates. One could, after all, create a “burner” keypair for deployment and then throw it away, as long as you could convince your users that you’d actually thrown it away. That is, of course, impossible to actually prove – but I can totally see a dApp glossing over that point to users who aren’t savvy enough to recognize the security issue in order to gain a competitive advantage due to their greater gas efficiency. (And then, once that gets normalized, someone will hold onto the “ephemeral” EOA keys and do a rugpull.)

  1. Require set code transactions to contain two different signatures.

This is the best I could think of to avoid the first problem from point #2 (gas sponsorship), but it doesn’t avoid the second and would not only require a second ecrecover but increase the TX storage costs for fullnodes to boot.


If it’s inevitable that 7702 will be used to deploy proxies, perhaps we could add a mechanism to allow that usecase to maintain 3607 protection. That could be as simple as introducing a special type of delegation designator that’s not allowed to be updated by a set code transaction. Perhaps this could be paired with an exception to EIP-3541 allowing direct creation of contracts with delegation designators, or some new opcode like CREATE3, or maybe a modification to the authorization format to add a flag to enable immutability; in any case, it should be no more expensive than deploying a proxy via deterministic signature without the 3607 protection immutability provides.

Reading through the EIP, I noticed that sweeping becomes much more expensive with EIP-7702 compared to EIP-3074. The main issue is the PER_EMPTY_ACCOUNT_COST which is added for every address swept, adding significant gas costs if sweeping lots of wallets.
Any thoughts about this?

This is still an extremely contrived example. If people want to “reverse” their delegation then can delegate to 0x0. If a contract wants to detect this, they will either need an external service to submit a delegation to the EOA in question to get that link like you described, or they need to prove against the state root.

Since delegating to a zero address doesn’t let an EOA do anything special and doesn’t change the fact that post-Prague they can delegate to a non-zero address at any moment, I don’t see an issue with how it is currently specified.

This is only paid if the account does not exist in the trie, otherwise the cost is 2,500.

1 Like