EIP-4758: Deactivate selfdestruct

2 Likes

Complete verkle trie construction for motivation: HackMD - Collaborative Markdown Knowledge Base
Analysis on applications that would be affected by this change: Impact Analysis of Neutering SELFDESTRUCT - Dev Update #2 - HackMD

1 Like

Abstract says:

The new functionality will be only to send all Ether in the account to the caller.

I believe you intended to say it sends to a beneficiary (instruction input address) and not the caller.

Also I’ll paste @chfast’s comment from draft PR here:

You forgot to mention that SENDALL still terminates execution.

Should it be repriced, as it’s now only updating balance?

The SELFDESTRUCT has one additional quirk not handled here: when the beneficiary is the selfdestructing address itself the balance is burned instead of being transferred.

Agreed that it should be mentioned explicitly in the EIP: EIP-4758: Deactivate selfdestruct by dankrad · Pull Request #4758 · ethereum/EIPs · GitHub.

But the new behavior can also be inferred from the EIP: the account removal doesn’t happen so a SENDALL with self as beneficiary is basically a no-op that just terminates execution of the current frame.

GitHub - jwasinger/eth-selfdestruct-analysis . This is an updated impact analysis which looks at usage of SELFDESTRUCT after the London hard fork and identifies contracts with large holdings that could be affected by the changes in EIP-4758

As mentioned by @chfast SELFDESTRUCT can be used to burn ETH by ‘selfdestructing’ to the current address. There is another quirk however which is changed by this EIP:

SELFDESTRUCT does not immediately destroy code and send the balance. This is done after all call frames are done and thus every opcode of the transaction has been executed. Only then are the following steps executed:

1. Send all ETH of the contract to the beneficiary
2. Destroy the contract (code = empty, balance = empty, nonce = 0, balance = 0)

Due to this order it is thus possible to destroy ETH. Also, notice that it is possible to do “multiple” selfdestructs by calling the selfdestruct from another contract multiple times. It is possible to first SELFDESTRUCT to address A and then SELFDESTRUCT to address B. In this case, the beneficiary is B, not A. If this changes, it should be specified on the EIP. It now seems that SENDALL sends all ETH of the current contract to the beneficiary and immediately exits the current call frame - which I guess is fine, but the EIP also states that it “renames” SELFDESTRUCT to SENDALL which is due to these quirks not really the case.

I don’t believe this is correct. The ETH is sent immediately. @gumb0 has double-checked this.

Oops, you are right, have semi-deleted my post.

I am a consumer of the reincarnation upgrade pattern. I built an NFT contract ownership system (0x000000000000c57CF0A1f923d44527e703F1ad70 on every chain) to facilitate this pattern. It helps us upgrade our contract without needing to re-approve and migrate every token for every protocol. Our storage footprint on the protocol would be much larger without SELFDESTRUCT. The SLOAD+DELEGATECALL pattern, especially after Berlin, costs way too much for practical use in gas-denominated auctions, so we cannot use it.

I am willing to pay millions in gas to facilitate code changes. I do not see why code must be immutable but not storage. Perhaps there is a fair way to price a code change, and we could introduce a replacement opcode like SETCODE.

The main drawback of SELFDESTRUCT right now from an engineering perspective is that it doesn’t take place until the end of the transaction, so I need two separate transactions to do the upgrade. This has prevented wider adoption, as you could not safely upgrade a token, for example, without risking being sandwiched.