Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CREATE2 documentation is incorrect #375

Open
SKYBITDev3 opened this issue Sep 10, 2023 · 4 comments
Open

CREATE2 documentation is incorrect #375

SKYBITDev3 opened this issue Sep 10, 2023 · 4 comments

Comments

@SKYBITDev3
Copy link

SKYBITDev3 commented Sep 10, 2023

In the Openzeppelin documentation of CREATE2 it states that:

New addresses are a function of:

  • 0xFF, a constant that prevents collisions with CREATE
  • The sender’s own address
  • A salt (an arbitrary value provided by the sender)
  • The to-be-deployed contract’s bytecode
new_address = hash(0xFF, sender, salt, bytecode)

CREATE2 guarantees that if sender ever deploys bytecode using CREATE2 and the provided salt, it will be stored in new_address.

This is incorrect as the sender is not used in the calculation of the address by the CREATE2 opcode itself. It's the address of the contract that calls the create2 function (the "CREATE2 factory") that's used for the calculation.

EIP-1014: Skinny CREATE2 doesn't explain what the input address is very clearly, but the Yul documentation of create2 at https://docs.soliditylang.org/en/v0.8.21/yul.html#opcodes is much clearer, stating "current contract’s address":

create2(v, p, n, s)   C create new contract with code mem[p…(p+n)) at address keccak256(0xff . this . s . keccak256(mem[p…(p+n))) and send v wei and return the new address, where 0xff is a 1 byte value, this is the current contract’s address as a 20 byte value and s is a big-endian 256-bit value; returns 0 on error

Gladly, the Openzeppelin CREATE2 library code correctly uses address(this) (and not msg.sender (or caller() in yul) as the documentation suggests).

However, factory contracts that use CREATE2 or CREATE3 libraries may first hash msg.sender with the user-provided salt before passing that into create2, e.g.:

https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/c20941bbed15dd2c571fc5578b98f8a39a653dbd/contracts/deploy/Deployer.sol#L31

https://github.com/ZeframLou/create3-factory/blob/06ec0ff36d41853dcd4399fbe2127aef801c4077/src/CREATE3Factory.sol#L21

This helps to prevent address clashes between different accounts that use the same salt. i.e. factoring in the sender may be done on a higher level, not in the library or EVM level. So you can't definitively state

CREATE2 guarantees that if sender ever deploys bytecode using CREATE2 and the provided salt, it will be stored in new_address.

as it depends on whether or not msg.sender is hashed with salt in the factory contract.

An example of a CREATE2 factory that doesn't use the sender is this popular one from Ethereum core developers Nick Johnson and Micah Zoltu: deterministic-deployment-proxy. It just passes the user-provided salt (calldataload(0)) straight into create2:
https://github.com/Arachnid/deterministic-deployment-proxy/blob/b3bb19c5aa8af6d9424fd66a234116a1e8adc3bf/source/deterministic-deployment-proxy.yul#L12. In my tests, changing the calling account resulted in the same deployment address. In such a case, it'd then be up to the factory user to ensure uniqueness via the salt.

For more details of using CREATE2 and CREATE3 and the various related issues see my repository: SKYBIT-Keyless-Deployment.

@frangio
Copy link
Contributor

frangio commented Sep 12, 2023

The "sender" from the perspective of contract creation is the factory, so I don't think the text is necessarily wrong, but I can see that it might be confusing. How would you rephrase it?

@SKYBITDev3
Copy link
Author

SKYBITDev3 commented Sep 12, 2023

Does sender mean msg.sender? The way the content is written for CREATE and CREATE2 makes it seem so.

@SKYBITDev3
Copy link
Author

The CREATE2 EVM opcode is called in a contract (a "factory"), but calculating the expected address using msg.sender in the contract won't produce the correct result. It's the factory contract's own address that must be used (address(this)). So it'd be better not to use the word sender to avoid confusion.

@SKYBITDev3
Copy link
Author

@LikeASardine this issue thread is about OpenZeppelin's documentation.

If you want to deploy contracts on multiple blockchains to the same address then see https://github.com/SKYBITDev3/SKYBIT-Keyless-Deployment .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants