There is a widely known misconception that all contracts are immutable, that their ABIs are firm and we can always rely on the ABI we have to decode the contract logic. We can also trust that the contract is safe for us to interact with as it’s been audited… Well, the truth is far from that, at least for how the EVM stands as of now! There are proposals attempting to alter this behaviour.
I came about this realization whilst trying to create a contract_creations
table. More specifically after I realized that there is something called a self_destruct
call (here). This specific call destroys* the contract and sends all remaining tokens stored in the contract to a designated address. This is not a problem at all if one could not redeploy bytecode (contract code) on top of the same address, but they actually can! That’s the problem!
https://tenor.com/view/frustrated-ugh-headache-gif-7532429">Frustrated
How can they do that you might ask? Well, it’s because of create2
the more deterministic functionality, allowing developers to re-deploy on top of the same address
. But don’t take my word for it, let’s read about it.
CREATE
vs CREATE2
CREATE
a new address is created as such:
new_address = hash(sender, nonce)
sender
the wallet address creating the new address.nonce
is something that increases with each transaction the sender
address does on-chain, so it basically establishes that each address created will be different since sender
+ nonce
combination is unique.bytecode
and that it is not deterministic. In the sense that:
0xlead420690000000000000000000000000000000
I would have to compute which sender
+ nonce
would create this, which is a pretty hefty computation if even feasible.CREATE2
a new address is created as such:
new_address = hash(0xFF, sender, salt, bytecode)
sender
the wallet address creating the new address.salt
is an arbitrary value provided by the sender.bytecode
the contract code to be deployed.0xFF
is a constant that prevents collisions with CREATE
.bytecode
using CREATE2
which of course can lead to potential security vulnerabilities.Let’s look at contracts that have been redeployed on the Ethereum
mainnet. I will also provide the code one can use on BigQuery
to follow along with this investigation.
The following code snippet, when sorted by count_times_created
descending yields the following results:
to_address
in creation traces designates the new_address
that is created.
We can notice a few things from just looking at the top 10 by count_times_created
:
to_address
is null
???
rpc
endpoint BigQuery
is using does not have a fallback for fetching the new_address
in some cases. Or something completely different. I do not believe that this is an EVM flaw, but just to be absolutely certain, let’s verify instead of believe (deep dive below):
null
InvestigationWe’ve updated our priors and we have seen that different contracts can be redeployed on top of the same address which is the side-effect or intended effect of the CREATE2
+ self_destruct
implementations.
To address duplicates with different bytecodes, use the first code snippet found here.