1

I would like to prove that a contract, that is going to be deployed, matches specific code and potentially with a specific state too.

For example, Bob say's he is going to deploy a contract that looks like this:

pragma solidity ^0.4.0;

contract SimpleStorage {
    uint storedData;

    function set(uint x) public {
        storedData = x;
    }
}

I'd like to whitelist this contract in my own contract before he deploys it. For example, maybe I keep a mapping of approved address that will be able to call my function. Though, the problem is, I don't know what Bob's SimpleStorage contract address will be.

But I do know that his contract will have this exact code, and that the functions will have ever been called yet (i.e. storedData is empty).

From what I think I know about the EVM, each deployed contract is designated a hash that is used by a Merkel tree. Any state updates to the contract change this hash slightly. I think this might be one method as I could whitelist the hash instead of the address, but I am unsure if this hash can be predicted before deployment.

So maybe the main question are:

  1. Is this understanding of contract hashes correct?

  2. Can you know what contract hash will have before it's deployed? For example, just from how the code looks and assuming no functions have ever been called.

  3. If no for (2), can you deploy it to a testnet, check the hash, and assume it will be the same on mainnet?

Maybe there is a better way of doing this you might be able to point out. For example, maybe I could whitelist Bob's address and trust all the contracts he deploys. But this has the problem that he can deploy any contract and not just SimpleStorage, which would be a vector of attack for my contract.

Would love to hear your thoughts, thank you!

1 Answer 1

1

One way to do this is to use the create2 opcode. When using this opcode (e.g. via a contract factory) the address of the contract will depend on the deployment code. The deployment code runs the constructor to initialize the storage and stores the contract code on the blockchain. With this you can calculate the address of the contract ahead of time and use it already for whitelisting.

This process, known as counterfactual deployment, is used by well known Ethereum tools such as the Gnosis Safe or OpenZepplin

5
  • Thank you, I think this is exactly what I was looking for. It sounds like Bob will be able to do expectedAddress = getCreate2Address(from, salt, byteCodeHash), and I could whitelist the expectedAddress beforehand where from is Bob. I do have a few more quick questions if you happen to know: (1) For the kind of scenario I described, what would be a good way to figure out a salt to use? (2) How does Bob use this Create2 function during his contract deployment, aren't these limited to contract deployed from contracts? (3) How does Bob generate and hash the bytecode to get byteCodeHash? Feb 20 at 0:51
  • And lastly, if Create2 can only be called by contracts, does this mean that Bob is still going to need to rely on my contract to have a method that uses create2() code for his contract deployment, rather than him deploy it on his own from his own address? Feb 20 at 15:16
  • (1) Depends on your usecase, but the easiest would be to always use 0. (2) There are public factories that can be used. E.g. github.com/gnosis/safe-singleton-factory or github.com/Arachnid/deterministic-deployment-proxy. (3) Just keccak hash the deployment code (see: github.com/OpenZeppelin/openzeppelin-contracts/blob/…)
    – Richard
    Feb 21 at 8:47
  • Thank you again, Richard! I just have one last question: I seem to be reading some conflicting information about "contracts deployed with Create2 cannot have contructors". In this OZ blog post, they specifically use an initializer function to get around some problem there. Doesn't what is happening in their code here encode parameters for a constructor? Would love some clarification there Feb 21 at 15:36
  • It depends very much on what you want to do. In most cases you can use the normal deployment code with a constructor and send it to the deployment factory. Of you use a proxy you will most of the time require an initializer.
    – Richard
    Feb 21 at 22:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.