Add a SET_INDESTRUCTIBLE (0xA8) opcode that prevents the contract from calling SELFDESTRUCT (0xff).


Should it be permanent or should there be a way to rollback?

The flag set by the opcode would last for the duration of the transaction, so it is temporary (though if the first byte of a contract is the opcode then of course it will trigger every time and be unavoidable, which is the intention).

Can this new OPCODE be used to signal if the contract implement or not self destruct?

If is set to false, then you can’t destroy that specific contract.


If the first byte of the code of a contract is this opcode, then that contract cannot selfdestruct.

1 Like

I’m thinking more into if you have implement the self destruct function the opcode is “true”. Is not if is possible to remove the contract, but more this contract can everything is place to be removed.


Basically can we inside a smart contract know that other smart contract can be removed.

Is important in the case when a dev want to whitelist smart contracts on chain.

I like this EIP. It makes contracts and libraries safer.

It makes proxy contracts and diamonds safer because they rely on delegatecall which can pull in code from other contracts.

This EIP prevents delegatecall from accidentally or maliciously destroying proxy contracts and diamonds and prevents the contracts/libraries that proxy contracts and diamonds rely on from disappearing. This is good.

1 Like

The intended use case would be for contracts to make their first byte of code be the SET_INDESTRUCTIBLE opcode if they wish…

However, the spec doesn’t say what should happen if SET_INDESTRUCTIBLE is encountered on PC!=0

Some other questions.

  1. Let’s say we have C with SET_INDESTRUCTIBLE at 0. Contract X does delegatecall(c) && selfdestruct. Does C successfully selfdestruct?
  2. Same scenarion with C. What about callcode(c)?

In general, is the globals.indestructible scoped? I assume it is (by which I mean it’s journalled, and scope-revertals removes stuff from it)

  1. I think that if SET_INDESTRUCTIBLE is encountered on PC!=0, it should be treated as a no-op to avoid any weird edge cases. However, forcing it to be the first byte does make its use case less flexible and I’m open to lifting this restriction.
  2. C should not successfully self destruct when using delegatecall if it is set as indestructible.
  3. C should also not successfully self destruct when using callcode if it is set as indestructible.

I also believe SET_INDESTRUCTIBLE should be implemented as a variable local to each execution frame. I think it is unnecessary to make it a global variable, as the delegatecall/callcode edge case can still be resolved with a local boolean variable implementation.

Proposed update to EIP-2937 spec: https://github.com/ethereum/EIPs/pull/3186
Local variable implementation in geth client: https://github.com/lightclient/go-ethereum/pull/7

I think this EIP is great, as it sets optional restriction/extension rules on the EVM context of future-deployed contracts.
But I think its scope should be extended: There might be other features we would like to enable/restrict in the future.

So I would suggest to add it as “RULES” opcode, which receives a single bitmask param.
the first bit is SET_INDESTRUCTIBLE, with the semantics defined by this EIP.
all other bits are REQUIRED to be zero, and the opcode should REVERT in case any is set.
In a future EIP (and fork), more semantics can be given to those bits, without requiring a new opcode for each.
The downside is that the prefix this new opcode generates is 3 bytes instead of 1: "PUSH1 1 RULES"

This doesn’t just make proxies / ‘diamonds’ safer, it makes them so much safer that it enables a categorically different mode of interaction where proxy actions / scripts can be properly sandboxed and so trustlessly composed within a single proxy script