Support every EVM chain + counterfactual contracts via CREATE2
CREATE2 allows sourcify to be useful on any EVM chain. It's extremely useful to be able to verify counterfactual addresses.
It would look similar to https://sourcify.dev/, just with two additional fields: sender address and salt. The "contract address" field would be then be the output instead of the input.
For convenience the source code could come from an already verified contract (as this infrastructure is already there), or any url. In this case a custom constructor data field would be useful.
Thinking about this more, deploying and verifying a contract similar to https://solidity-by-example.org/app/create2/ is an easy way to do this. Perhaps this could be standardized
Thanks for the suggestion. We can maybe have a chainId of 0 to indicate the CREATE2 addresses.
As far as I understood from the EIP, the init_code is the contract creation code (i.e. tx.data) and this also includes the constructor arguments. So if the user adds the constructor arguments they will be appended to the init_code and will be part of the address computation. I.e. different constructor arguments result in different contract addresses, right?
One thing crossed my mind is if we should allow verification of counterfactual contracts or if we should require the contract to be deployed alrea at one network. On the one hand, this is the whole idea of the CREATE2 opcode, on the other hand, I can see this being a kind of an attack vector. If we accept all CREATE2 addresses, anyone can bloat the repository with non-existing contracts by iterating the salt.
Can you also elaborate more on "standardization"?
Yes, we would not want to allow non-existant contracts. Here's a quick example that hopefully demonstrates better (and the need for some 'standardization'):
Let's say I want to use CREATE2 for a user onboarding scenario for a contract based wallet - give a user address x, but don't deploy the contract until necessary.
But before a user sends some ether, NFTs, etc. to this address, the user wants to verify the counterfactual address's code, even if it's not deployed.
As an example, lets say my desired Wallet code is Wallet.sol. I can upload and deploy it: 0x05e2a930aa689cded59a10c7f0b8a8c0967beb4a. I verify the source in the standard way.
Now, lets say I want to prove to you that counterfactual address 0x58CD30e7c8d65b90f2224034F597231eDd0D0c72 =
new Wallet(0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B, 0x6262998Ced04146fA42253a5C0AF90CA02dfd2A3), so you can start using it - on any EVM chain, and without needing to deploy it.
Here's an example of how sourcify could do that:
| Verify |
|---|
| address of a verified, deployed contract OR contract source code |
| after above is entered, constructor arguments, from ABI |
| deployer address |
| salt |
| Verify | example |
|---|---|
| verified contract address | 0x05e2a930aa689cded59a10c7f0b8a8c0967beb4a |
| constructor argument - owner | 0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B |
| constructor argument - admin | 0x6262998Ced04146fA42253a5C0AF90CA02dfd2A3 |
| deployer address | 0xe8c16c17d879c9bd52a855241b21e4ce5fe5dcf3 |
| salt | 0x01 |
| output | 0x58CD30e7c8d65b90f2224034F597231eDd0D0c72 |
Here is an example showing this can kind of be done via etherscan's UI, see code for more comments. It hardcodes the 'verified contract's initCode and ABI to match the Wallet.sol from above, but in reality sourcify would fetch these using either the verified contract or the uploaded files.
https://ropsten.etherscan.io/address/0xe8c16c17d879c9bd52a855241b21e4ce5fe5dcf3#readContract

This verifies 0x58CD30e7c8d65b90f2224034F597231eDd0D0c72 =
new Wallet(0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B, 0x6262998Ced04146fA42253a5C0AF90CA02dfd2A3), or any a = new Wallet(x,y), while only needing to verify Wallet once - only one copy in the repository.
Sure enough, when I run deployWalletExample, 0x58CD30e7c8d65b90f2224034F597231eDd0D0c72 is equal to new Wallet(0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B, 0x6262998Ced04146fA42253a5C0AF90CA02dfd2A3)
Thanks for the detailed description and the contract example! It is much clearer
One thing we need to make sure is to ensure we have the correct contract creation code as the creation code after compilation might differ from the one being deployed, e.g. when there are immutables in the contract which will be injected into the creation code in deploy time. One way can be to use make use of the Javascript EVM as outlined here: https://ethereum.stackexchange.com/questions/94396/how-to-get-the-actual-runtime-bytecode-from-creation-bytecode-and-constructor-ar by @FabijanC
Another thing, again, is if or when we store the counterfactual contract in the repository. I'd imagine we have a form with:
- deployer address
- salt
- constructor arguments
- An already verified contract address+network OR contract source code
Then the output is the counterfactual address 0x58CD30e7c8d65b90f2224034F597231eDd0D0c72 in your example. This way any contract at the same address on any EVM chain is guaranteed to have this source code deployed. About saving to repository I have some thoughts:
-
Immediately save Wallet.sol to
/contracts/(full | partial)_match/0/0x58CD30e7c8d65b90f2224034F597231eDd0D0c72after user generates the counterfactual address. My concern was there are nearly infinite many addresses possible by changing the salt. Question is how much of a concern is this? Maybe can we ask for a CAPTCHA? -
Save to
/contracts/(full | partial)_match/0/0x58CD30e7c8d65b90f2224034F597231eDd0D0c72if there is a contract deployed at any of the EVM chains supported. This way we avoid storing contracts that will never be used. Users still can check if the same counterfactual contract address is generated by the inputs they gave, but we won't store it. Question: Will looking for all EVM chains be a problem? -
Save to
/contracts/(full | partial)_match/0/0x58CD30e7c8d65b90f2224034F597231eDd0D0c72if there is a contract deployed at the given address and network. We ask the user exactly where the contract is deployed at but we still save it as chainId=0 i.e. any chain.
I'd also like to know what are @chriseth 's thoughts on this when he's back.
CREATE2 is depends on the creation bytecode, not the runtime bytecode, so no EVM should be needed. Nothing new even needs to be stored in the sourcify repo - just ideally there is a nice API+UI+URL for providing the creation bytecode hash, constructor arguments, salt, and deployer address, and getting back the CREATE2 address + verified source code. ("Nothing new needs to be stored" if the creation bytecode hash is given as a pointer to an existing verified contract). Technically this could all be done any wallet/explorer itself using what sourcify already offers; it would just be nice to, for example, give a link sourcify.dev/create2?baseContract=X&salt=Y&deployer=Z, and have that jump straight to a page with the verified source code + verified address.
A brief recap about this activity:
- new api
/verify/create2- with the following parameters (need to choose either one of the last two parameters)
deployerAddress: address: the factory contract that will deploy using create2salt: bytes32: the salt given to create2constructorArgs: json<type,value>[]: the arguments of the constructor[baseContract: address]: the address of the already Sourcify-verified contract to deploy using create2[files: json]: a json containing the files used to generate the bytecode to pass to create2
- that will verify a counterfactual contract and save it using chainId 0
- with the following parameters (need to choose either one of the last two parameters)
- new page on sourcify sourcify.dev/create2
- users need to choose if they want to upload files or to put an address of a Sourcify-verified smart contract
- the ui will generate inputs rappresenting the constructor argument
- salt is asked
- deployer contract is asked
- on form submit
/verify/create2api is called
@ligi above you see a recap of this activity. If we allow anyone to call /verify/create2, there can be potentially a spam problem. One of the solution could be to use a Captcha. @kuzdogan told me that you already used captcha in the past, and maybe you could suggest us a good library to use