Yes it’s paid only if the account does not exist in the trie, however this will usually be the case when sweeping tokens from deposit addresses. User submits tokens to the address, the address is not added to the trie, therefore sweeping those tokens will include the cost of PER_EMPTY_ACCOUNT_COST.
Security is all about finding contrived examples. It’s always easier to recognize that an implicit assumption can be broken before someone comes up with a useful reason to break it.
In this case, the original rationale for not including a mechanism to remove a delegation was the implicit assumption that a delegation to 0x0
would be indistinguishable on-chain from having no delegation at all. That indistinguishability property doesn’t hold. To be clear, we’re now talking about using a new, different rationale to justify omitting such a mechanism – not “it confers an attacker no possible advantage”, but “it confers an attacker no useful advantage.”
I think that’s a dangerous rationale, even if it does end up being a technically sound analysis of the presently-contemplated system, because future upgrades tend to make things better and more useful. For example, you just said that the difference between the two states (never-delegated and delegated to 0x0
) is negligible because introspecting it requires setting up an external service to submit a delegation transaction, but that’s a specific pain point I brought up previously. The rationale for not specifying a way for a contract to set a delegation without an external transaction submitter was merely that such a mechanism was out of scope for this EIP, not that its absence was necessary to justify the omission of a true undelegation mechanism.
Besides, omitting a round-trip undelegation mechanism from this EIP actually doesn’t make the system simpler – it just socializes the complexity to future maintainers. Imagine, for example, that there’s some other delegation standard we want to implement in the future. (Obviously, we’re using 0xef0100
as a prefix rather than simply 0xef
here for a reason!) But because this EIP fails to specify a way to get back to a canonical “not delegated” state, we force any future work which might want to use the 0xef
prefix for EOAs for something else to handle upgrades from the “delegated-to-nothing” state as well as the “blank-code” state. That adds sharp edges I’d really prefer that future EIP authors not have to avoid.
I’ll admit that I don’t understand yet why the “obvious” solution – special-casing delegations to 0x0
as blanking an account’s code – wasn’t included from the start, which makes me worried that I’ve missed some attack vector that approach might enable or other obvious downside. But I do think it’s just poor design to build a switch that you can nominally turn on and off, where turning it off puts you into a different state than before turning it on.
(Note that this puts a 2500-gas upper limit on the cost to introspect an account’s delegation designator. You could easily set a delegation designator for an address with a well-known private key in the same transaction you tried to do the introspection, and you’d have an atomic operation.)
Another reason we might want to be able to fully remove delegation is that a delegation to 0x0 increases many costs of using one’s account, since the EVM will try to fetch code from 0x0 costing an additional COLD_ACCOUNT_READ_COST
. This applies to receiving ETH and receiving NFTs (which uses EXTCODESIZE
).
Isn’t anyone worried that EIP-7702 introduces a major phishing risk in conjunction with 1271 signature verification?
Example:
NFT Trading Protocol Verifies ECDSA Signature for order approval. When ECDSA verification fails and code length > 0, protocol falls back to 1271 isValidSignatureNow
check. This pattern is probably common in many protocols.
In scenario above, using 7702, you could phish a signature that attaches malicious contract code to the NFT holder, submit fake order data with a sale price of 0 eth, and then return MAGIC
from isValidSignatureNow
to authorize the zero-value order.
There will probably be many such cases.
Another phishing vector that doesn’t involve protocols at all:
- Drainer phishes as many signatures as possible to attach unverified, malicious code to their EOA. For the sake of argument, say they are able to harvest hundreds of such approvals because nobody checks to see if the attached code is verified. And even if it is verified, nobody reads the code anyway.
- Drainer executs a
drain
transaction on a smart contract they have deployed. The 7702 special tx includes dozens of phished victims at once. drain
loops over the supplied victim addresses, callingdrainAssets
on the malicious code that has been attached to victims’ accounts. It searches for valuable assets like ETH/WETH/USDC/etc and valuable NFTs, callingtransfer
to the attacker on everything it can find that is considered valuable.
The only thing that can prevent this is tokens that implement Limit Break’s ERC20-C/ERC721-C/ERC1155-C with security levels set to block OTC.
Look, the people that get phished for their entire net worth are just going to have to take one for the team as this new technology advances and appropriate safeguards are put in place after thorough post-mortem analysis.
There are already many phishing vectors. Users should know what they are signing and that’s the wallet’s responsibility. These signatures don’t resemble other signatures so older wallet software won’t be prone to this unless they were already prone to much worse attacks (such as eth_sign
: What is 'eth sign' and why is it a risk? | MetaMask Help Center 🦊♥️).
Wallet security is hard and at first it will be hard to support this feature safely. However, the feature is good and so technology will improve to support it.
Most of the current phishing vectors revolve around signing EIP712 signatures that are semi-readable, rely on open approvals, don’t risk native funds, and are generally easy to simulate the potential impact of signing.
This EIP has the potential to drain all valuable assets, including native funds, with a far less readable signature that is harder to simulate. I would not be surprised to see wallets take a highly centralized approach to what contracts are allowed to be signed. It will be a step backward for security and decentralization while being pushed towards the finish line at a remarkable pace.
If there’s a significant enough security incident will we end up with ETCV2?
“User’s should know what they are signing”.
I completely agree - that’s why I love EOAs and self-sovereign wallets. Account Abstraction is about onboarding people that don’t understand crypto/wallets at all. You can’t expect them to know/understand what they are signing if the only way to onboard them is to hide the Web3 wallet from them altogether.
If you phish a signature for a delegate authorization, all bets are off. It has root. You don’t need clever protocol shenanigans at that point.
You could, of course, also have just phished a signature for a transaction which called transfer
directly; the only difference here is that it lets you batch TXes, which is frankly a feature and not a bug. I’m looking forward to there being a simple and cheap way to sweep all assets from an address with a compromised key to a new one.
Do I understand correct, that in result of this eip:
- solidity
address(EOA).codehash
will return one-time code hash value during the transaction?- Was there analysis of consequences for existing
address.codehash
users (github finds some)?
- Was there analysis of consequences for existing
- There will be no means to identify within EVM runtime that addresses bytecode is temporarly set?
Im guessing answer is in these lines
The delegation designation uses the banned opcode 0xef from EIP-3541 to designate the code has a special purpose. This designator requires all code retrieving operations to follow the address pointer to fill the account’s observable code. The following instructions are impacted: EXTCODESIZE, EXTCODECOPY, EXTCODEHASH, CALL, CALLCODE, STATICCALL, DELEGATECALL.
But perhaps someone can translate to simpler language? Does this formulation meaning is that external contracts will observe EOA as an EOA?
Also thinking if moving ERC7744 to eip could allow one-time deployers to specify codehash instead of sending full bytecode as @wjmelements suggests?
added proposal pr for this, just in case: Add EIP: GETCONTRACT opcode by peersky · Pull Request #8935 · ethereum/EIPs · GitHub
This is a more compelling perspective.
This shouldn’t be the case since the codehash is determined by the account’s delegation. It can change, but it isn’t a “one-time”.
As long as the account is not delegated or is delegated to an empty account, contracts will observe it as an EOA.
I elaborated github query today morning
To validate my concern, I spent some time digging in and discovered a repo which I think would become vulnerable in result and is deployed on Ethereum:
https://etherscan.io/address/0x0000000000b1827b4959F2805E4b480D8799FCbB#code
Their public method originate internally calls _callCustody that reverts based on user-provided custodian
field, which is being checked via extcodehash
.
With 7702, adversary could temporary delegate to make it look like he is valid custodian, inside originate the transferSpentItems
method would send assets to adversaries EOA.
I found some more later:
Yes that’s interesting.
Basically contracts could so far assume that codehash would be a reliable indicator of the behavior of an account. Unless the behavior was that of a proxy it could be assumed to be immutable. EIP-7702 changes that by introducing “invisible proxies”.
I think this is a very legitimate security concern.
I don’t really understand this point, can you expand on the issue? IMO until cancun, it was possible to selfdestruct an account and deploy alternative code. So an account having different code isn’t really a new problem.
I think the difference is that for that to happen the account had to have selfdestruct or delegatecall in its code, so observing codehash (with known preimage) you would know the code could change. Now the code change can be a “surprise” because there is no indicator.
This would be solved making EXTCODE* not follow delegations.
Wouldn’t it break the 7702 provided functionality itself? E.g Externally called contracts that rely their isContract on hash?
Right, but what exactly is an example where a “surprise” code change would cause harm? In general you either fully trust the code you’re calling into or you don’t trust it at all and must be defensive.
An example would be a contract that transfers tokens to an account only if its codehash is the known codehash of a timelock, assuming the rules of the timelock will be respected. With EIP-7702 an EOA would be able to masquerade as a timelock and bypass the restrictions.
In the example above you trusted the known code, and you reasoned you could trust the account on the basis of its codehash.
This is a little contrived. In practice the contract would probably deploy the timelocks itself rather than checking the codehash, or it would require a CREATE2 address and validate the entire creation code and parameters.
I searched superficially and wasn’t able to find real world examples that would be vulnerable to this kind of attack. But it doesn’t sound that far-fetched to me.